Merge commit '883847ef2f6479f3639b522f2b5f7a195670b591' into 14542.0.0

BUG=b/222349736
TEST=local BE run
RELEASE_NOTE=None

Change-Id: I84600109e60dbcff59a374acc97ea8d0c67d09d9
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 7e2a640..beaae89 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,6 +1,6 @@
 {
         "python.autoComplete.extraPaths": [
-                "${workspaceFolder}/third_party",
+                "${workspaceFolder}/third_party"
         ],
         "python.testing.cwd": "${workspaceFolder}",
         "python.testing.unittestArgs": [
@@ -16,7 +16,8 @@
         "python.testing.nosetestsEnabled": false,
         "python.testing.unittestEnabled": true,
         "python.sortImports.args": [
-                "--settings-path=${workspaceFolder}/.vscode/",
+                "--settings-path=${workspaceFolder}/.vscode/"
         ],
         "python.linting.pylintEnabled": true,
+        "python.formatting.provider": "yapf"
 }
diff --git a/DIR_METADATA b/DIR_METADATA
index 455513e..a6fc2cb 100644
--- a/DIR_METADATA
+++ b/DIR_METADATA
@@ -1,3 +1,17 @@
+# Metadata information for this directory.
+#
+# For more information on DIR_METADATA files, see:
+#   https://source.chromium.org/chromium/infra/infra/+/HEAD:go/src/infra/tools/dirmd/README.md
+#
+# For the schema of this file, see Metadata message:
+#   https://source.chromium.org/chromium/infra/infra/+/HEAD:go/src/infra/tools/dirmd/proto/dir_metadata.proto
+
 buganizer {
-  component_id: 1037860
+  component_id: 1027774  # ChromeOS > Infra > Build
 }
+
+buganizer_public {
+  component_id: 1037860  # Chrome OS Public Tracker > Services > Infra > Build
+}
+
+team_email: "chromeos-build-discuss@google.com"
diff --git a/OWNERS.au b/OWNERS.au
index c27c88d..be5da43 100644
--- a/OWNERS.au
+++ b/OWNERS.au
@@ -3,7 +3,8 @@
 # found in the LICENSE file.
 
 # Auto-update Team
-ahassani@chromium.org
 dhaddock@chromium.org
+hbarnor@chromium.org
 kimjae@chromium.org
-vyshu@chromium.org
+kyleshima@chromium.org
+yuanpengni@chromium.org
diff --git a/OWNERS.build b/OWNERS.build
index cfc6149..65bb806 100644
--- a/OWNERS.build
+++ b/OWNERS.build
@@ -4,7 +4,10 @@
 
 # Build Team
 cjmcdonald@chromium.org
+rchandrasekar@google.com
 saklein@chromium.org
 sfrolov@google.com
+sloanjohnson@google.com
 vapier@chromium.org
+xcl@google.com
 zland@google.com
diff --git a/OWNERS.ci b/OWNERS.ci
index 083dabf..760ef76 100644
--- a/OWNERS.ci
+++ b/OWNERS.ci
@@ -4,14 +4,17 @@
 
 # CI team
 andrewlamb@chromium.org
+azrahman@google.com
+bshai@google.com
 ctmcnamara@chromium.org
 dhanyaganesh@chromium.org
 engeg@google.com
 gredelston@google.com
 hardtmad@chromium.org
 jackneus@google.com
+jaquesc@google.com
 jaredloucks@google.com
 juahurta@google.com
 mikenichols@chromium.org
 navil@google.com
-smcallis@google.com
+tbain@google.com
diff --git a/OWNERS.fw b/OWNERS.fw
index 579c5ca..507cdb4 100644
--- a/OWNERS.fw
+++ b/OWNERS.fw
@@ -4,7 +4,7 @@
 
 pgeorgi@chromium.org
 martinroth@chromium.org
-furquan@chromium.org
+kramasub@chromium.org
 jwerner@chromium.org
 twawrzynczak@chromium.org
 hungte@chromium.org
diff --git a/PRESUBMIT.cfg b/PRESUBMIT.cfg
index bb7de3b..9a7af1d 100644
--- a/PRESUBMIT.cfg
+++ b/PRESUBMIT.cfg
@@ -1,6 +1,7 @@
 [Hook Scripts]
 cros lint = bin/cros lint ${PRESUBMIT_FILES}
 preupload_dump_config = bin/preupload_dump_config
+cros_ide_test = ide_tooling/cros-ide/preupload_hook.sh ${PRESUBMIT_FILES}
 
 [Hook Overrides]
 json_check: true
diff --git a/README.md b/README.md
index ab2fce1..b0b7c23 100644
--- a/README.md
+++ b/README.md
@@ -150,7 +150,7 @@
 Every Python file in Chromite is accompanied by a corresponding `*_unittest.py`
 file. Running a particular file's unit tests is best done via
 ```shell
-~/trunk/chromite $ ./run_tests example_file_unittest.py
+chromite $ ./run_tests example_file_unittest.py
 ```
 
 This script initializes a Python 3 virtualenv with necessary test dependencies
@@ -162,6 +162,15 @@
 Tests will not run in a standalone git checkout of chromite. Use the repo-based
 flow described above to obtain a functional-testing environment.
 
+### Network Tests
+
+By default, any test that reaches out to the network (those wrapped in a
+`@cros_test_lib.pytestmark_network_test` decorator) will not be run. To include
+these tests, add the `--network` option:
+```shell
+~/trunk/chromite $ ./run_tests --network -- ...
+```
+
 ### Writing unit tests
 
 Chromite's unit tests make use of pytest
diff --git a/api/README.md b/api/README.md
index 0a05eee..659b686 100644
--- a/api/README.md
+++ b/api/README.md
@@ -10,15 +10,16 @@
 created to provide a stable interface for the CI builders. The proto files (in
 [chromite/infra/proto](#chromite/infra/proto/)) define the services/RPCs
 provided by the API. The modules in [controller/](./controller/) are the entry
-points for the RPCs defined in the proto files. The Build API is invoked via the
-`build_api` script, which takes 4 arguments; the name of the endpoint being
-called (e.g. chromite.api.SdkService/Create), and the input, output, and
-optional config protos, which are provided as paths to files containing the
-respective JSON or protobuf-binary encoded messages.
+points for the RPCs defined in the proto files.
 
 ### Calling An Endpoint
 
-To manually call an endpoint, e.g. for testing, the
+The Build API is invoked via the `build_api` script, which takes 4 arguments;
+the name of the endpoint being called (e.g. chromite.api.SdkService/Create), and
+the request, response, and optional config protos, which are provided as paths
+to files containing the respective JSON or protobuf-binary encoded messages.
+
+However, to manually call an endpoint, the
 [gen_call_scripts](./contrib/README.md#gen_call_scripts_call_templates_and-call_scripts)
 process is recommended, it makes calling a specific endpoint much simpler.
 Please also contribute new example input files when you add new endpoints!
@@ -27,97 +28,13 @@
 though. You'll need to build out an instance of the request message and write it
 to a file, and then just call the `build_api` script.
 
-The only tricky part is getting the compiled protobuf. If you're working in
-recipes or in chromite the problem has already been addressed. Otherwise, you'll
-need to figure out a process that works for you depending on your language and
-purpose. For immediate, local work, compiling the proto with protoc should be
-relatively straightforward, but for production services consulting the CrOS CI
-team may be worthwhile.
+### Tutorials and References
 
-## API Developer Guide
+See the [Build API Tutorials](./tutorials/0_introduction.md) for code lab style
+instructions on how to make an endpoint.
 
-This section contains information for developers contributing to the Build API.
-
-### Special Build API Proto Behavior
-
-The Build API has some special, automatic functionality that triggers for a few
-specific proto messages/fields. These are meant to facilitate some specific
-aspects of the Build API and reduce boilerplate code.
-
-#### Service & Method Options
-
-The service and method options extensions in `chromite/api/build_api.proto`
-define some key information about the implementation of the endpoint.
-
-The first are the `module` and `implementation_name` fields, in the service and
-method options respectively, that tell the Build API how to call the endpoint.
-The service's `module` option is required, and defines the name of the
-[controller](#controller) module where the service's RPCs are implemented. The
-method's `implementation_name` field is optional, and defines the name of the
-function in the service's controller module for the RPC. When the
-`implementation_name` is not given, the API expects the function to have the
-same name as the RPC in the proto.
-
-The two options extensions also define the `service_chroot_assert` and
-`method_chroot_assert` fields, respectively. These two fields allow defining
-whether the endpoint must run `INSIDE` or `OUTSIDE` the chroot, or if either is
-fine when not set. The service's option is the default for all of its RPCs, and
-the RPC's method option overrides it when set.
-
-#### `INSIDE` chroot endpoints
-
-At first the `INSIDE` behavior can be somewhat confusing, but is designed to
-reduce boilerplate by automating chroot interactions. When writing an endpoint
-that needs to run inside the chroot, setting the chroot assertion to `INSIDE` is
-not required, but is strongly recommended for the sake of simplifying the
-implementation and standardizing the chroot interactions.
-
-All endpoints that do use the `INSIDE` functionality must have a
-`chromiumos.Chroot` field, but are otherwise free to use whatever it needs. The
-Build API parses the `chromiumos.Chroot` field, removes it from the input, then
-executes the endpoint inside the chroot. The endpoint's implementation can be
-written as if it is always inside the chroot, because while Build API
-invocations are always made from outside the chroot, it ensures the
-implementation does not even get imported until after it has entered the chroot.
-
-#### `INSIDE` Chroot `Path` Utilities
-
-The automatic chroot handling means inserting and extracting artifacts is not
-possible manually. This gap has been filled by the `Path`, `ResultPath`, and
-`SyncedDir` messages, defined in `chromiumos/common.proto`, that allows the
-implementations to always behave as if they are working with local files without
-considering chroot pathing implications.
-
-The `Path` message tells the Build API a path, and whether the path is inside or
-outside of the chroot. A `Path` message in a request can be used to inject a
-file or folder into the chroot for the endpoint to use. Before entering the
-chroot, the Build API copies the path into a temporary directory inside the
-chroot, and changes the path in the request sent to the inside-chroot invocation
-of the endpoint to point to that inside chroot path. For example, if you need
-`/working/directory/image.bin` for an endpoint inside the chroot, the Build API
-will create a `/path/to/chroot/tmp/rand-tmp-dir/`, copy in `image.bin`, and then
-the implementation running inside the chroot will be given
-`/tmp/rand-tmp-dir/image.bin`.
-
-The `ResultPath` message provides a similar functionality for extracting paths
-from the chroot. The`ResultPath` message itself must be defined in the request,
-and is analogous to passing a function an output directory. To use, simply set
-the paths of the response `Path` messages to the files or directories that need
-to be extracted from the chroot. After the endpoint execution completes, all
-`Path` messages in the response are copied into the given result path, and the
-paths in the response are updated to reflect their final location. Worth noting,
-the implementation does not require gathering artifacts to a specific location
-inside the chroot, the Build API will handle gathering the files into the
-ResultPath outside the chroot.
-
-The `SyncedDir` message in a request provides a blanket, bidirectional sync of a
-directory. Any files present in the specified directory are copied into a temp
-directory in the chroot before it is executed, then after it finishes the source
-directory is emptied, and all files in the chroot directory are copied out to
-the source directory. This message can be useful for situations where the
-directory structure or contents is not necessarily important, for example,
-setting a process' log directory to the `SyncedDir` path allows extracting all
-the log files.
+See the [Build API References](./references) for a quick, detailed reference on
+specific topics.
 
 ## Directory Reference
 
diff --git a/api/compile_build_api_proto.py b/api/compile_build_api_proto.py
index ff6daff..5e7bf8c 100644
--- a/api/compile_build_api_proto.py
+++ b/api/compile_build_api_proto.py
@@ -139,7 +139,7 @@
       git.Clone(chromeos_config_path,
                 '%s/chromiumos/config' % constants.EXTERNAL_GOB_URL,
                 depth=1
-      )
+                )
 
     # Only compile the subset we need for the API.
     subdirs = [
diff --git a/api/contrib/call_templates/android__write_lkgb_input.json b/api/contrib/call_templates/android__write_lkgb_input.json
new file mode 100644
index 0000000..e7782c2
--- /dev/null
+++ b/api/contrib/call_templates/android__write_lkgb_input.json
@@ -0,0 +1,4 @@
+{
+  "android_package": "android-vm-sc",
+  "android_version": "8888888"
+}
diff --git a/api/contrib/call_templates/metadata__system_image_metadata_input.json b/api/contrib/call_templates/metadata__system_image_metadata_input.json
new file mode 100644
index 0000000..109209a
--- /dev/null
+++ b/api/contrib/call_templates/metadata__system_image_metadata_input.json
@@ -0,0 +1,8 @@
+{
+  "sysroot": {
+    "buildTarget": {
+      "name": "%(build_target)s"
+    },
+    "path": "/build/%(build_target)s"
+  }
+}
diff --git a/api/contrib/call_templates/package__get_builder_metadata_input.json b/api/contrib/call_templates/package__get_builder_metadata_input.json
new file mode 100644
index 0000000..9611be1
--- /dev/null
+++ b/api/contrib/call_templates/package__get_builder_metadata_input.json
@@ -0,0 +1,5 @@
+{
+  "build_target": {
+    "name": "%(build_target)s"
+  }
+}
diff --git a/api/contrib/call_templates/test__build_test_service_containers_input.json b/api/contrib/call_templates/test__build_test_service_containers_input.json
new file mode 100644
index 0000000..8af38ad
--- /dev/null
+++ b/api/contrib/call_templates/test__build_test_service_containers_input.json
@@ -0,0 +1,8 @@
+{
+    "build_target": {
+        "name": "%(build_target)s"
+    },
+    "chroot": {
+		"path": "%(chroot)s"
+	}
+}
diff --git a/api/contrib/call_templates/toolchain__get_clippy_lints_input.json b/api/contrib/call_templates/toolchain__emerge_with_linting_input.json
similarity index 100%
rename from api/contrib/call_templates/toolchain__get_clippy_lints_input.json
rename to api/contrib/call_templates/toolchain__emerge_with_linting_input.json
diff --git a/api/controller/android.py b/api/controller/android.py
index f003420..0b21ecd 100644
--- a/api/controller/android.py
+++ b/api/controller/android.py
@@ -4,6 +4,7 @@
 
 """Android operations."""
 
+import logging
 import os
 from typing import TYPE_CHECKING
 
@@ -81,8 +82,9 @@
   output_proto.status = android_pb2.MARK_STABLE_STATUS_SUCCESS
   # TODO(crbug/904939): This should move to service/android.py and the port
   # should be finished.
+  android_atom_to_build = None
   try:
-    android_atom_to_build = packages.uprev_android(
+    result = packages.uprev_android(
         android_package=package_name,
         chroot=chroot,
         build_targets=build_targets,
@@ -90,6 +92,8 @@
         android_version=android_version,
         skip_commit=skip_commit,
     )
+    if result.revved:
+      android_atom_to_build = result.android_atom
   except packages.AndroidIsPinnedUprevError as e:
     # If the uprev failed due to a pin, CI needs to unpin and retry.
     android_atom_to_build = e.new_android_atom
@@ -118,3 +122,37 @@
     _config: The call config.
   """
   osutils.SafeUnlink(ANDROIDPIN_MASK_PATH)
+
+
+def _WriteLKGBResponse(_input_proto, output_proto, _config):
+  """Fake WriteLKGB response."""
+  output_proto.modified_files.append('fake_file')
+
+
+@faux.success(_WriteLKGBResponse)
+@faux.empty_error
+@validate.require('android_package', 'android_version')
+@validate.validation_complete
+def WriteLKGB(input_proto, output_proto, _config):
+  android_package = input_proto.android_package
+  android_version = input_proto.android_version
+  android_package_dir = android.GetAndroidPackageDir(android_package)
+
+  # Attempt to read current LKGB, if available.
+  current_lkgb = None
+  try:
+    current_lkgb = android.ReadLKGB(android_package_dir)
+  except android.MissingLKGBError:
+    logging.info('LKGB file is missing, creating a new one.')
+  except android.InvalidLKGBError:
+    logging.warning('Current LKGB file is invalid, overwriting.')
+
+  # Do nothing if LKGB is already set to the requested version.
+  if current_lkgb == android_version:
+    logging.warning('LKGB of %s is already %s, doing nothing.',
+                    android_package, android_version)
+    return
+
+  # Actually update LKGB.
+  lkgb = android.WriteLKGB(android_package_dir, android_version)
+  output_proto.modified_files.append(lkgb)
diff --git a/api/controller/android_unittest.py b/api/controller/android_unittest.py
index 8e28f62..f14319e 100644
--- a/api/controller/android_unittest.py
+++ b/api/controller/android_unittest.py
@@ -130,7 +130,9 @@
 
   def testCallsCommandCorrectly(self):
     """Test that commands.MarkAndroidAsStable is called correctly."""
-    self.uprev.return_value = 'cat/android-1.2.3'
+    self.uprev.return_value = packages.UprevAndroidResult(
+        revved=True,
+        android_atom='cat/android-1.2.3')
     atom = common_pb2.PackageInfo()
     atom.category = 'cat'
     atom.package_name = 'android'
@@ -150,7 +152,7 @@
 
   def testHandlesEarlyExit(self):
     """Test that early exit is handled correctly."""
-    self.uprev.return_value = ''
+    self.uprev.return_value = packages.UprevAndroidResult(revved=False)
     android.MarkStable(self.input_proto, self.response, self.api_config)
     self.uprev.assert_called_once_with(
         android_package=self.input_proto.package_name,
@@ -211,3 +213,115 @@
     android.UnpinVersion(None, None, self.mock_call_config)
     safeunlink.assert_not_called()
     # android.UnpinVersion does not modify the response.
+
+
+class WriteLKGBTest(cros_test_lib.MockTestCase, api_config.ApiConfigMixin):
+  """Unittests for WriteLKGB."""
+
+  def setUp(self):
+    self._output_proto = android_pb2.WriteLKGBResponse()
+
+  def testValidateOnly(self):
+    """Test that a validate only call does not execute any logic."""
+    mock_write_lkgb = self.PatchObject(service_android, 'WriteLKGB')
+
+    req = android_pb2.WriteLKGBRequest(android_package='android-package',
+                                       android_version='android-version')
+    android.WriteLKGB(req, self._output_proto, self.validate_only_config)
+
+    mock_write_lkgb.assert_not_called()
+
+  def testMockCall(self):
+    """Test that a mock call does not execute logic, returns mocked value."""
+    mock_write_lkgb = self.PatchObject(service_android, 'WriteLKGB')
+
+    req = android_pb2.WriteLKGBRequest(android_package='android-package',
+                                       android_version='android-version')
+    android.WriteLKGB(req, self._output_proto, self.mock_call_config)
+
+    mock_write_lkgb.assert_not_called()
+    self.assertSequenceEqual(self._output_proto.modified_files, ['fake_file'])
+
+  def testFailsIfAndroidPackageMissing(self):
+    """Fails if android_package is missing."""
+    req = android_pb2.WriteLKGBRequest(android_version='android-version')
+    with self.assertRaises(cros_build_lib.DieSystemExit):
+      android.WriteLKGB(req, self._output_proto, self.api_config)
+
+  def testFailsIfAndroidVersionMissing(self):
+    """Fails if android_version is missing."""
+    req = android_pb2.WriteLKGBRequest(android_package='android-package')
+    with self.assertRaises(cros_build_lib.DieSystemExit):
+      android.WriteLKGB(req, self._output_proto, self.api_config)
+
+  def testSuccess(self):
+    """Successful request."""
+    mock_read_lkgb = self.PatchObject(service_android, 'ReadLKGB',
+                                      return_value='old-version')
+    mock_write_lkgb = self.PatchObject(service_android, 'WriteLKGB',
+                                       return_value='mock_file')
+    self.PatchObject(service_android, 'GetAndroidPackageDir',
+                     return_value='android-package-dir')
+
+    req = android_pb2.WriteLKGBRequest(android_package='android-package',
+                                       android_version='android-version')
+    android.WriteLKGB(req, self._output_proto, self.api_config)
+
+    mock_read_lkgb.assert_called_once_with('android-package-dir')
+    mock_write_lkgb.assert_called_once_with('android-package-dir',
+                                            'android-version')
+    self.assertSequenceEqual(self._output_proto.modified_files, ['mock_file'])
+
+  def testSameVersion(self):
+    """Nothing is modified if LKGB is already the same version."""
+    mock_read_lkgb = self.PatchObject(service_android, 'ReadLKGB',
+                                      return_value='android-version')
+    mock_write_lkgb = self.PatchObject(service_android, 'WriteLKGB')
+    self.PatchObject(service_android, 'GetAndroidPackageDir',
+                     return_value='android-package-dir')
+
+    req = android_pb2.WriteLKGBRequest(android_package='android-package',
+                                       android_version='android-version')
+    android.WriteLKGB(req, self._output_proto, self.api_config)
+
+    mock_read_lkgb.assert_called_once_with('android-package-dir')
+    mock_write_lkgb.assert_not_called()
+    self.assertSequenceEqual(self._output_proto.modified_files, [])
+
+  def testMissingLKGB(self):
+    """Proceed if LKGB file is currently missing."""
+    mock_read_lkgb = self.PatchObject(
+        service_android, 'ReadLKGB',
+        side_effect=service_android.MissingLKGBError())
+    mock_write_lkgb = self.PatchObject(service_android, 'WriteLKGB',
+                                       return_value='mock_file')
+    self.PatchObject(service_android, 'GetAndroidPackageDir',
+                     return_value='android-package-dir')
+
+    req = android_pb2.WriteLKGBRequest(android_package='android-package',
+                                       android_version='android-version')
+    android.WriteLKGB(req, self._output_proto, self.api_config)
+
+    mock_read_lkgb.assert_called_once_with('android-package-dir')
+    mock_write_lkgb.assert_called_once_with('android-package-dir',
+                                            'android-version')
+    self.assertSequenceEqual(self._output_proto.modified_files, ['mock_file'])
+
+  def testInvalidLKGB(self):
+    """Proceed if LKGB file currently contains invalid content."""
+    mock_read_lkgb = self.PatchObject(
+        service_android, 'ReadLKGB',
+        side_effect=service_android.InvalidLKGBError())
+    mock_write_lkgb = self.PatchObject(service_android, 'WriteLKGB',
+                                       return_value='mock_file')
+    self.PatchObject(service_android, 'GetAndroidPackageDir',
+                     return_value='android-package-dir')
+
+    req = android_pb2.WriteLKGBRequest(android_package='android-package',
+                                       android_version='android-version')
+    android.WriteLKGB(req, self._output_proto, self.api_config)
+
+    mock_read_lkgb.assert_called_once_with('android-package-dir')
+    mock_write_lkgb.assert_called_once_with('android-package-dir',
+                                            'android-version')
+    self.assertSequenceEqual(self._output_proto.modified_files, ['mock_file'])
diff --git a/api/controller/artifacts.py b/api/controller/artifacts.py
index 797d02a..cffea03 100644
--- a/api/controller/artifacts.py
+++ b/api/controller/artifacts.py
@@ -6,7 +6,7 @@
 
 import logging
 import os
-from typing import Any, NamedTuple
+from typing import Any, NamedTuple, Optional, TYPE_CHECKING
 
 from chromite.api import controller
 from chromite.api import faux
@@ -16,7 +16,6 @@
 from chromite.api.controller import sysroot as sysroot_controller
 from chromite.api.controller import test as test_controller
 from chromite.api.gen.chromite.api import artifacts_pb2
-from chromite.api.gen.chromite.api import toolchain_pb2
 from chromite.api.gen.chromiumos import common_pb2
 from chromite.lib import chroot_lib
 from chromite.lib import constants
@@ -25,6 +24,8 @@
 from chromite.service import artifacts
 from chromite.service import test
 
+if TYPE_CHECKING:
+  from chromite.api import api_config
 
 class RegisteredGet(NamedTuple):
   """An registered function for calling Get on an artifact type."""
@@ -46,7 +47,10 @@
 @faux.success(ExampleGetResponse)
 @validate.exists('result_path.path.path')
 @validate.validation_complete
-def Get(input_proto, output_proto, _config):
+def Get(
+    input_proto: artifacts_pb2.GetRequest,
+    output_proto: artifacts_pb2.GetResponse,
+    _config: 'api_config.ApiConfig'):
   """Get all artifacts.
 
   Get all artifacts for the build.
@@ -55,9 +59,9 @@
   stop uploading it via the individual bundler function.
 
   Args:
-    input_proto (GetRequest): The input proto.
-    output_proto (GetResponse): The output proto.
-    _config (api_config.ApiConfig): The API call config.
+    input_proto: The input proto.
+    output_proto: The output proto.
+    _config: The API call config.
   """
   output_dir = input_proto.result_path.path.path
 
@@ -111,7 +115,11 @@
 @faux.success(_BuildSetupResponse)
 @faux.empty_error
 @validate.validation_complete
-def BuildSetup(_input_proto, output_proto, _config):
+def BuildSetup(
+    _input_proto: artifacts_pb2.GetRequest,
+    output_proto: artifacts_pb2.GetResponse,
+    _config: 'api_config.ApiConfig'):
+
   """Setup anything needed for building artifacts
 
   If any artifact types require steps prior to building the package, they go
@@ -122,9 +130,9 @@
   individual bundler function.
 
   Args:
-    _input_proto (GetRequest): The input proto.
-    output_proto (GetResponse): The output proto.
-    _config (api_config.ApiConfig): The API call config.
+    _input_proto: The input proto.
+    output_proto: The output proto.
+    _config: The API call config.
   """
   # If any artifact_type says "NEEDED", the return is NEEDED.
   # Otherwise, if any artifact_type says "UNKNOWN", the return is UNKNOWN.
@@ -133,14 +141,14 @@
   return controller.RETURN_CODE_SUCCESS
 
 
-def _GetImageDir(build_root, target):
+def _GetImageDir(build_root: str, target: str) -> Optional[str]:
   """Return path containing images for the given build target.
 
   TODO(saklein) Expand image_lib.GetLatestImageLink to support this use case.
 
   Args:
-    build_root (str): Path to checkout where build occurs.
-    target (str): Name of the build target.
+    build_root: Path to checkout where build occurs.
+    target: Name of the build target.
 
   Returns:
     Path to the latest directory containing target images or None.
@@ -192,13 +200,16 @@
 @validate.require('build_target.name', 'output_dir')
 @validate.exists('output_dir')
 @validate.validation_complete
-def BundleImageZip(input_proto, output_proto, _config):
+def BundleImageZip(
+    input_proto: artifacts_pb2.BundleRequest,
+    output_proto: artifacts_pb2.BundleResponse,
+    _config: 'api_config.ApiConfig'):
   """Bundle image.zip.
 
   Args:
-    input_proto (BundleRequest): The input proto.
-    output_proto (BundleResponse): The output proto.
-    _config (api_config.ApiConfig): The API call config.
+    input_proto: The input proto.
+    output_proto: The output proto.
+    _config: The API call config.
   """
   target = input_proto.build_target.name
   output_dir = input_proto.output_dir
@@ -221,13 +232,16 @@
 @validate.require('build_target.name', 'output_dir')
 @validate.exists('output_dir')
 @validate.validation_complete
-def BundleTestUpdatePayloads(input_proto, output_proto, _config):
+def BundleTestUpdatePayloads(
+    input_proto: artifacts_pb2.BundleRequest,
+    output_proto: artifacts_pb2.BundleResponse,
+    _config: 'api_config.ApiConfig'):
   """Generate minimal update payloads for the build target for testing.
 
   Args:
-    input_proto (BundleRequest): The input proto.
-    output_proto (BundleResponse): The output proto.
-    _config (api_config.ApiConfig): The API call config.
+    input_proto: The input proto.
+    output_proto: The output proto.
+    _config: The API call config.
   """
   target = input_proto.build_target.name
   output_dir = input_proto.output_dir
@@ -265,13 +279,16 @@
 @faux.empty_error
 @validate.require('output_dir')
 @validate.exists('output_dir')
-def BundleAutotestFiles(input_proto, output_proto, config):
+def BundleAutotestFiles(
+    input_proto: artifacts_pb2.BundleRequest,
+    output_proto: artifacts_pb2.BundleResponse,
+    config: 'api_config.ApiConfig'):
   """Tar the autotest files for a build target.
 
   Args:
-    input_proto (BundleRequest): The input proto.
-    output_proto (BundleResponse): The output proto.
-    config (api_config.ApiConfig): The API call config.
+    input_proto: The input proto.
+    output_proto: The output proto.
+    config: The API call config.
   """
   output_dir = input_proto.output_dir
   target = input_proto.build_target.name
@@ -316,13 +333,16 @@
 @faux.empty_error
 @validate.require('output_dir')
 @validate.exists('output_dir')
-def BundleTastFiles(input_proto, output_proto, config):
+def BundleTastFiles(
+    input_proto: artifacts_pb2.BundleRequest,
+    output_proto: artifacts_pb2.BundleResponse,
+    config: 'api_config.ApiConfig'):
   """Tar the tast files for a build target.
 
   Args:
-    input_proto (BundleRequest): The input proto.
-    output_proto (BundleResponse): The output proto.
-    config (api_config.ApiConfig): The API call config.
+    input_proto: The input proto.
+    output_proto: The output proto.
+    config: The API call config.
   """
   target = input_proto.build_target.name
   output_dir = input_proto.output_dir
@@ -381,15 +401,18 @@
 @validate.exists('chroot.path')
 @validate.require('sysroot.path')
 @validate.validation_complete
-def FetchMetadata(input_proto, output_proto, _config):
+def FetchMetadata(
+    input_proto: artifacts_pb2.FetchMetadataRequest,
+    output_proto: artifacts_pb2.FetchMetadataResponse,
+    _config: 'api_config.ApiConfig'):
   """FetchMetadata returns the paths to all build/test metadata files.
 
   This implements ArtifactsService.FetchMetadata.
 
   Args:
-    input_proto (FetchMetadataRequest): The input proto.
-    output_proto (FetchMetadataResponse): The output proto.
-    config (api_config.ApiConfig): The API call config.
+    input_proto: The input proto.
+    output_proto: The output proto.
+    config: The API call config.
   """
   chroot = controller_util.ParseChroot(input_proto.chroot)
   sysroot = controller_util.ParseSysroot(input_proto.sysroot)
@@ -410,13 +433,16 @@
 @validate.require('output_dir', 'sysroot.path')
 @validate.exists('output_dir')
 @validate.validation_complete
-def BundleFirmware(input_proto, output_proto, _config):
+def BundleFirmware(
+    input_proto: artifacts_pb2.BundleRequest,
+    output_proto: artifacts_pb2.BundleResponse,
+    _config: 'api_config.ApiConfig'):
   """Tar the firmware images for a build target.
 
   Args:
-    input_proto (BundleRequest): The input proto.
-    output_proto (BundleResponse): The output proto.
-    _config (api_config.ApiConfig): The API call config.
+    input_proto: The input proto.
+    output_proto: The output proto.
+    _config: The API call config.
   """
   output_dir = input_proto.output_dir
   chroot = controller_util.ParseChroot(input_proto.chroot)
@@ -432,9 +458,10 @@
   archive = artifacts.BuildFirmwareArchive(chroot, sysroot, output_dir)
 
   if archive is None:
-    cros_build_lib.Die(
+    logging.warning(
         'Could not create firmware archive. No firmware found for %s.',
         sysroot_path)
+    return
 
   output_proto.artifacts.add().path = archive
 
@@ -450,13 +477,16 @@
 @validate.require('output_dir', 'sysroot.path')
 @validate.exists('output_dir')
 @validate.validation_complete
-def BundleFpmcuUnittests(input_proto, output_proto, _config):
+def BundleFpmcuUnittests(
+    input_proto: artifacts_pb2.BundleRequest,
+    output_proto: artifacts_pb2.BundleResponse,
+    _config: 'api_config.ApiConfig'):
   """Tar the fingerprint MCU unittest binaries for a build target.
 
   Args:
-    input_proto (BundleRequest): The input proto.
-    output_proto (BundleResponse): The output proto.
-    _config (api_config.ApiConfig): The API call config.
+    input_proto: The input proto.
+    output_proto: The output proto.
+    _config: The API call config.
   """
   output_dir = input_proto.output_dir
   chroot = controller_util.ParseChroot(input_proto.chroot)
@@ -488,13 +518,16 @@
 @faux.success(_BundleEbuildLogsResponse)
 @faux.empty_error
 @validate.exists('output_dir')
-def BundleEbuildLogs(input_proto, output_proto, config):
+def BundleEbuildLogs(
+    input_proto: artifacts_pb2.BundleRequest,
+    output_proto: artifacts_pb2.BundleResponse,
+    config: 'api_config.ApiConfig'):
   """Tar the ebuild logs for a build target.
 
   Args:
-    input_proto (BundleRequest): The input proto.
-    output_proto (BundleResponse): The output proto.
-    config (api_config.ApiConfig): The API call config.
+    input_proto: The input proto.
+    output_proto: The output proto.
+    config: The API call config.
   """
   output_dir = input_proto.output_dir
   sysroot_path = input_proto.sysroot.path
@@ -532,13 +565,16 @@
 @faux.empty_error
 @validate.exists('output_dir')
 @validate.validation_complete
-def BundleChromeOSConfig(input_proto, output_proto, _config):
+def BundleChromeOSConfig(
+    input_proto: artifacts_pb2.BundleRequest,
+    output_proto: artifacts_pb2.BundleResponse,
+    _config: 'api_config.ApiConfig'):
   """Output the ChromeOS Config payload for a build target.
 
   Args:
-    input_proto (BundleRequest): The input proto.
-    output_proto (BundleResponse): The output proto.
-    _config (api_config.ApiConfig): The API call config.
+    input_proto: The input proto.
+    output_proto: The output proto.
+    _config: The API call config.
   """
   output_dir = input_proto.output_dir
   sysroot_path = input_proto.sysroot.path
@@ -554,10 +590,9 @@
 
   sysroot = sysroot_lib.Sysroot(sysroot_path)
   chromeos_config = artifacts.BundleChromeOSConfig(chroot, sysroot, output_dir)
-  if chromeos_config is None:
-    cros_build_lib.Die(
-        'Could not create ChromeOS Config payload. No config found for %s.',
-        sysroot.path)
+  if not chromeos_config:
+    return
+
   output_proto.artifacts.add().path = os.path.join(output_dir, chromeos_config)
 
 
@@ -611,13 +646,16 @@
 @validate.require('chroot.path', 'test_results_dir', 'output_dir')
 @validate.exists('output_dir')
 @validate.validation_complete
-def BundleVmFiles(input_proto, output_proto, _config):
+def BundleVmFiles(
+    input_proto: artifacts_pb2.BundleVmFilesRequest,
+    output_proto: artifacts_pb2.BundleResponse,
+    _config: 'api_config.ApiConfig'):
   """Tar VM disk and memory files.
 
   Args:
-    input_proto (BundleVmFilesRequest): The input proto.
-    output_proto (BundleResponse): The output proto.
-    _config (api_config.ApiConfig): The API call config.
+    input_proto: The input proto.
+    output_proto: The output proto.
+    _config: The API call config.
   """
   chroot = controller_util.ParseChroot(input_proto.chroot)
   test_results_dir = input_proto.test_results_dir
@@ -628,49 +666,6 @@
   for archive in archives:
     output_proto.artifacts.add().path = archive
 
-def _BundleAFDOGenerationArtifactsResponse(input_proto, output_proto, _config):
-  """Add test tarball AFDO file to a successful response."""
-  output_proto.artifacts.add().path = os.path.join(
-      input_proto.output_dir, 'artifact1')
-
-
-_VALID_ARTIFACT_TYPES = [toolchain_pb2.BENCHMARK_AFDO,
-                         toolchain_pb2.ORDERFILE]
-@faux.success(_BundleAFDOGenerationArtifactsResponse)
-@faux.empty_error
-@validate.require('build_target.name', 'output_dir')
-@validate.is_in('artifact_type', _VALID_ARTIFACT_TYPES)
-@validate.exists('output_dir')
-@validate.exists('chroot.chrome_dir')
-@validate.validation_complete
-def BundleAFDOGenerationArtifacts(input_proto, output_proto, _config):
-  """Generic function for creating tarballs of both AFDO and orderfile.
-
-  Args:
-    input_proto (BundleChromeAFDORequest): The input proto.
-    output_proto (BundleResponse): The output proto.
-    _config (api_config.ApiConfig): The API call config.
-  """
-  chrome_root = input_proto.chroot.chrome_dir
-  output_dir = input_proto.output_dir
-  artifact_type = input_proto.artifact_type
-
-  build_target = controller_util.ParseBuildTarget(input_proto.build_target)
-  chroot = controller_util.ParseChroot(input_proto.chroot)
-
-  try:
-    is_orderfile = bool(artifact_type is toolchain_pb2.ORDERFILE)
-    results = artifacts.BundleAFDOGenerationArtifacts(
-        is_orderfile, chroot, chrome_root,
-        build_target, output_dir)
-  except artifacts.Error as e:
-    cros_build_lib.Die('Error %s raised in BundleSimpleChromeArtifacts: %s',
-                       type(e), e)
-
-  for file_name in results:
-    output_proto.artifacts.add().path = file_name
-
-
 def _ExportCpeReportResponse(input_proto, output_proto, _config):
   """Add test cpe results to a successful response."""
   output_proto.artifacts.add().path = os.path.join(
@@ -682,13 +677,16 @@
 @faux.success(_ExportCpeReportResponse)
 @faux.empty_error
 @validate.exists('output_dir')
-def ExportCpeReport(input_proto, output_proto, config):
+def ExportCpeReport(
+    input_proto: artifacts_pb2.BundleRequest,
+    output_proto: artifacts_pb2.BundleResponse,
+    config: 'api_config.ApiConfig'):
   """Export a CPE report.
 
   Args:
-    input_proto (BundleRequest): The input proto.
-    output_proto (BundleResponse): The output proto.
-    config (api_config.ApiConfig): The API call config.
+    input_proto: The input proto.
+    output_proto: The output proto.
+    config: The API call config.
   """
   chroot = controller_util.ParseChroot(input_proto.chroot)
   output_dir = input_proto.output_dir
@@ -724,13 +722,16 @@
 @validate.require('build_target.name', 'output_dir')
 @validate.exists('output_dir')
 @validate.validation_complete
-def BundleGceTarball(input_proto, output_proto, _config):
+def BundleGceTarball(
+    input_proto: artifacts_pb2.BundleRequest,
+    output_proto: artifacts_pb2.BundleResponse,
+    _config: 'api_config.ApiConfig'):
   """Bundle the test image into a tarball suitable for importing into GCE.
 
   Args:
-    input_proto (BundleRequest): The input proto.
-    output_proto (BundleResponse): The output proto.
-    _config (api_config.ApiConfig): The API call config.
+    input_proto: The input proto.
+    output_proto: The output proto.
+    _config: The API call config.
   """
   target = input_proto.build_target.name
   output_dir = input_proto.output_dir
diff --git a/api/controller/artifacts_unittest.py b/api/controller/artifacts_unittest.py
index f7b73d1..0ba737d 100644
--- a/api/controller/artifacts_unittest.py
+++ b/api/controller/artifacts_unittest.py
@@ -6,13 +6,13 @@
 
 import os
 import pathlib
+from typing import Optional
 from unittest import mock
 
 from chromite.api import api_config
 from chromite.api.controller import artifacts
 from chromite.api.controller import controller_util
 from chromite.api.gen.chromite.api import artifacts_pb2
-from chromite.api.gen.chromite.api import toolchain_pb2
 from chromite.api.gen.chromiumos import common_pb2
 from chromite.cbuildbot import commands
 from chromite.lib import chroot_lib
@@ -388,9 +388,9 @@
   def testBundleFirmwareNoLogs(self):
     """BundleFirmware dies when no firmware found."""
     self.PatchObject(commands, 'BuildFirmwareArchive', return_value=None)
-    with self.assertRaises(cros_build_lib.DieSystemExit):
-      artifacts.BundleFirmware(self.sysroot_request, self.response,
-                               self.api_config)
+    artifacts.BundleFirmware(self.sysroot_request, self.response,
+                             self.api_config)
+    self.assertEqual(len(self.response.artifacts), 0)
 
 
 class BundleFpmcuUnittestsTest(BundleTestCase):
@@ -537,12 +537,12 @@
                      [mock.call(mock.ANY, self.sysroot, self.output_dir)])
 
   def testBundleChromeOSConfigNoConfigFound(self):
-    """An error is raised if the config payload isn't found."""
+    """Empty results when the config payload isn't found."""
     self.PatchObject(artifacts_svc, 'BundleChromeOSConfig', return_value=None)
 
-    with self.assertRaises(cros_build_lib.DieSystemExit):
-      artifacts.BundleChromeOSConfig(self.sysroot_request, self.response,
-                                     self.api_config)
+    artifacts.BundleChromeOSConfig(self.sysroot_request, self.response,
+                                   self.api_config)
+    self.assertFalse(self.response.artifacts)
 
 
 class BundleTestUpdatePayloadsTest(cros_test_lib.MockTempDirTestCase,
@@ -646,15 +646,19 @@
 
     self.response = artifacts_pb2.BundleResponse()
 
-  def _GetRequest(self, chroot=None, sysroot=None, build_target=None,
-                  output_dir=None):
+  def _GetRequest(
+      self,
+      chroot: Optional[str] = None,
+      sysroot: Optional[str] = None,
+      build_target: Optional[str] = None,
+      output_dir: Optional[str] = None) -> artifacts_pb2.BundleRequest:
     """Helper to create a request message instance.
 
     Args:
-      chroot (str): The chroot path.
-      sysroot (str): The sysroot path.
-      build_target (str): The build target name.
-      output_dir (str): The output directory.
+      chroot: The chroot path.
+      sysroot: The sysroot path.
+      build_target: The build target name.
+      output_dir: The output directory.
     """
     return artifacts_pb2.BundleRequest(
         sysroot={'path': sysroot, 'build_target': {'name': build_target}},
@@ -753,17 +757,19 @@
 
     self.response = artifacts_pb2.BundleResponse()
 
-  def _GetInput(self, chroot=None, sysroot=None, test_results_dir=None,
-                output_dir=None):
+  def _GetInput(
+      self,
+      chroot: Optional[str] = None,
+      sysroot: Optional[str] = None,
+      test_results_dir: Optional[str] = None,
+      output_dir: Optional[str] = None) -> artifacts_pb2.BundleVmFilesRequest:
     """Helper to build out an input message instance.
 
     Args:
-      chroot (str|None): The chroot path.
-      sysroot (str|None): The sysroot path relative to the chroot.
-      test_results_dir (str|None): The test results directory relative to the
-        sysroot.
-      output_dir (str|None): The directory where the results tarball should be
-        saved.
+      chroot: The chroot path.
+      sysroot: The sysroot path relative to the chroot.
+      test_results_dir: The test results directory relative to the sysroot.
+      output_dir: The directory where the results tarball should be saved.
     """
     return artifacts_pb2.BundleVmFilesRequest(
         chroot={'path': chroot}, sysroot={'path': sysroot},
@@ -850,181 +856,6 @@
 
 
 
-class BundleAFDOGenerationArtifactsTestCase(
-    cros_test_lib.MockTempDirTestCase, api_config.ApiConfigMixin):
-  """Unittests for BundleAFDOGenerationArtifacts."""
-
-  @staticmethod
-  def mock_die(message, *args):
-    raise cros_build_lib.DieSystemExit(message % args)
-
-  def setUp(self):
-    self.chroot_dir = os.path.join(self.tempdir, 'chroot_dir')
-    osutils.SafeMakedirs(self.chroot_dir)
-    temp_dir = os.path.join(self.chroot_dir, 'tmp')
-    osutils.SafeMakedirs(temp_dir)
-    self.output_dir = os.path.join(self.tempdir, 'output_dir')
-    osutils.SafeMakedirs(self.output_dir)
-    self.chrome_root = os.path.join(self.tempdir, 'chrome_root')
-    osutils.SafeMakedirs(self.chrome_root)
-    self.build_target = 'board'
-    self.valid_artifact_type = toolchain_pb2.ORDERFILE
-    self.invalid_artifact_type = toolchain_pb2.NONE_TYPE
-    self.does_not_exist = os.path.join(self.tempdir, 'does_not_exist')
-    self.PatchObject(cros_build_lib, 'Die', new=self.mock_die)
-
-    self.response = artifacts_pb2.BundleResponse()
-
-  def _GetRequest(self, chroot=None, build_target=None, chrome_root=None,
-                  output_dir=None, artifact_type=None):
-    """Helper to create a request message instance.
-
-    Args:
-      chroot (str): The chroot path.
-      build_target (str): The build target name.
-      chrome_root (str): The path to Chrome root.
-      output_dir (str): The output directory.
-      artifact_type (artifacts_pb2.AFDOArtifactType):
-      The type of the artifact.
-    """
-    return artifacts_pb2.BundleChromeAFDORequest(
-        chroot={'path': chroot, 'chrome_dir': chrome_root},
-        build_target={'name': build_target},
-        output_dir=output_dir,
-        artifact_type=artifact_type,
-    )
-
-  def testValidateOnly(self):
-    """Quick check that a validate only call does not execute any logic."""
-    patch = self.PatchObject(artifacts_svc,
-                             'BundleAFDOGenerationArtifacts')
-    request = self._GetRequest(chroot=self.chroot_dir,
-                               build_target=self.build_target,
-                               chrome_root=self.chrome_root,
-                               output_dir=self.output_dir,
-                               artifact_type=self.valid_artifact_type)
-    artifacts.BundleAFDOGenerationArtifacts(request, self.response,
-                                            self.validate_only_config)
-    patch.assert_not_called()
-
-  def testMockCall(self):
-    """Test that a mock call does not execute logic, returns mocked value."""
-    patch = self.PatchObject(artifacts_svc,
-                             'BundleAFDOGenerationArtifacts')
-    request = self._GetRequest(chroot=self.chroot_dir,
-                               build_target=self.build_target,
-                               chrome_root=self.chrome_root,
-                               output_dir=self.output_dir,
-                               artifact_type=self.valid_artifact_type)
-    artifacts.BundleAFDOGenerationArtifacts(request, self.response,
-                                            self.mock_call_config)
-    patch.assert_not_called()
-    self.assertEqual(len(self.response.artifacts), 1)
-    self.assertEqual(self.response.artifacts[0].path,
-                     os.path.join(self.output_dir, 'artifact1'))
-
-  def testNoBuildTarget(self):
-    """Test no build target fails."""
-    request = self._GetRequest(chroot=self.chroot_dir,
-                               chrome_root=self.chrome_root,
-                               output_dir=self.output_dir,
-                               artifact_type=self.valid_artifact_type)
-    with self.assertRaises(cros_build_lib.DieSystemExit) as context:
-      artifacts.BundleAFDOGenerationArtifacts(request, self.response,
-                                              self.api_config)
-    self.assertEqual('build_target.name is required.',
-                     str(context.exception))
-
-  def testNoChromeRoot(self):
-    """Test no chrome root fails."""
-    request = self._GetRequest(chroot=self.chroot_dir,
-                               build_target=self.build_target,
-                               output_dir=self.output_dir,
-                               artifact_type=self.valid_artifact_type)
-    with self.assertRaises(cros_build_lib.DieSystemExit) as context:
-      artifacts.BundleAFDOGenerationArtifacts(request, self.response,
-                                              self.api_config)
-    self.assertEqual('chroot.chrome_dir path does not exist: ',
-                     str(context.exception))
-
-  def testNoOutputDir(self):
-    """Test no output dir fails."""
-    request = self._GetRequest(chroot=self.chroot_dir,
-                               build_target=self.build_target,
-                               chrome_root=self.chrome_root,
-                               artifact_type=self.valid_artifact_type)
-    with self.assertRaises(cros_build_lib.DieSystemExit) as context:
-      artifacts.BundleAFDOGenerationArtifacts(request, self.response,
-                                              self.api_config)
-    self.assertEqual('output_dir is required.',
-                     str(context.exception))
-
-  def testOutputDirDoesNotExist(self):
-    """Test output directory not existing fails."""
-    request = self._GetRequest(chroot=self.chroot_dir,
-                               build_target=self.build_target,
-                               chrome_root=self.chrome_root,
-                               output_dir=self.does_not_exist,
-                               artifact_type=self.valid_artifact_type)
-    with self.assertRaises(cros_build_lib.DieSystemExit) as context:
-      artifacts.BundleAFDOGenerationArtifacts(request, self.response,
-                                              self.api_config)
-    self.assertEqual(
-        'output_dir path does not exist: %s' % self.does_not_exist,
-        str(context.exception))
-
-  def testNoArtifactType(self):
-    """Test no artifact type."""
-    request = self._GetRequest(chroot=self.chroot_dir,
-                               build_target=self.build_target,
-                               chrome_root=self.chrome_root,
-                               output_dir=self.output_dir)
-    with self.assertRaises(cros_build_lib.DieSystemExit) as context:
-      artifacts.BundleAFDOGenerationArtifacts(request, self.response,
-                                              self.api_config)
-    self.assertIn('artifact_type (0) must be in',
-                  str(context.exception))
-
-  def testWrongArtifactType(self):
-    """Test passing wrong artifact type."""
-    request = self._GetRequest(chroot=self.chroot_dir,
-                               build_target=self.build_target,
-                               chrome_root=self.chrome_root,
-                               output_dir=self.output_dir,
-                               artifact_type=self.invalid_artifact_type)
-    with self.assertRaises(cros_build_lib.DieSystemExit) as context:
-      artifacts.BundleAFDOGenerationArtifacts(request, self.response,
-                                              self.api_config)
-    self.assertIn('artifact_type (%d) must be in' % self.invalid_artifact_type,
-                  str(context.exception))
-
-  def testOutputHandlingOnOrderfile(self,
-                                    artifact_type=toolchain_pb2.ORDERFILE):
-    """Test response output for orderfile."""
-    files = ['artifact1', 'artifact2', 'artifact3']
-    expected_files = [os.path.join(self.output_dir, f) for f in files]
-    self.PatchObject(artifacts_svc, 'BundleAFDOGenerationArtifacts',
-                     return_value=expected_files)
-
-    request = self._GetRequest(chroot=self.chroot_dir,
-                               build_target=self.build_target,
-                               chrome_root=self.chrome_root,
-                               output_dir=self.output_dir,
-                               artifact_type=artifact_type)
-
-    artifacts.BundleAFDOGenerationArtifacts(request, self.response,
-                                            self.api_config)
-
-    self.assertTrue(self.response.artifacts)
-    self.assertCountEqual(expected_files,
-                          [a.path for a in self.response.artifacts])
-
-  def testOutputHandlingOnAFDO(self):
-    """Test response output for AFDO."""
-    self.testOutputHandlingOnOrderfile(
-        artifact_type=toolchain_pb2.BENCHMARK_AFDO)
-
-
 class ExportCpeReportTest(cros_test_lib.MockTempDirTestCase,
                           api_config.ApiConfigMixin):
   """ExportCpeReport tests."""
@@ -1196,4 +1027,4 @@
     actual_filepaths = [fp.path.path for fp in response.filepaths]
     self.assertEqual(sorted(actual_filepaths), sorted(self.expected_filepaths))
     self.assertTrue(all([fp.path.location == common_pb2.Path.OUTSIDE
-        for fp in response.filepaths]))
+                         for fp in response.filepaths]))
diff --git a/api/controller/binhost.py b/api/controller/binhost.py
index 652eee6..3a5a24c 100644
--- a/api/controller/binhost.py
+++ b/api/controller/binhost.py
@@ -7,6 +7,7 @@
 import os
 import shutil
 import urllib.parse
+from typing import TYPE_CHECKING
 
 from chromite.api import controller
 from chromite.api import faux
@@ -19,6 +20,8 @@
 from chromite.lib import sysroot_lib
 from chromite.service import binhost
 
+if TYPE_CHECKING:
+  from chromite.api import api_config
 
 _OVERLAY_TYPE_TO_NAME = {
     binhost_pb2.OVERLAYTYPE_PUBLIC: constants.PUBLIC_OVERLAYS,
@@ -87,15 +90,18 @@
 @faux.success(_PrepareBinhostUploadsResponse)
 @faux.empty_error
 @validate.require('uri')
-def PrepareBinhostUploads(input_proto, output_proto, config):
+def PrepareBinhostUploads(
+    input_proto: binhost_pb2.PrepareBinhostUploadsRequest,
+    output_proto: binhost_pb2.PrepareBinhostUploadsResponse,
+    config: 'api_config.ApiConfig'):
   """Return a list of files to upload to the binhost.
 
   See BinhostService documentation in api/proto/binhost.proto.
 
   Args:
-    input_proto (PrepareBinhostUploadsRequest): The input proto.
-    output_proto (PrepareBinhostUploadsResponse): The output proto.
-    config (api_config.ApiConfig): The API call config.
+    input_proto: The input proto.
+    output_proto: The output proto.
+    config: The API call config.
   """
   if input_proto.sysroot.build_target.name:
     build_target_msg = input_proto.sysroot.build_target
@@ -152,16 +158,19 @@
 @faux.empty_error
 @validate.require('uri', 'sysroot.path')
 @validate.exists('uploads_dir')
-def PrepareDevInstallBinhostUploads(input_proto, output_proto, config):
+def PrepareDevInstallBinhostUploads(
+    input_proto: binhost_pb2.PrepareDevInstallBinhostUploadsRequest,
+    output_proto: binhost_pb2.PrepareDevInstallBinhostUploadsResponse,
+    config: 'api_config.ApiConfig'):
   """Return a list of files to upload to the binhost"
 
   The files will also be copied to the uploads_dir.
   See BinhostService documentation in api/proto/binhost.proto.
 
   Args:
-    input_proto (PrepareDevInstallBinhostUploadsRequest): The input proto.
-    output_proto (PrepareDevInstallBinhostUploadsResponse): The output proto.
-    config (api_config.ApiConfig): The API call config.
+    input_proto: The input proto.
+    output_proto: The output proto.
+    config: The API call config.
   """
   sysroot_path = input_proto.sysroot.path
 
@@ -211,15 +220,17 @@
 @faux.empty_error
 @validate.require('build_target.name', 'key', 'uri')
 @validate.validation_complete
-def SetBinhost(input_proto, output_proto, _config):
+def SetBinhost(input_proto: binhost_pb2.SetBinhostRequest,
+               output_proto: binhost_pb2.SetBinhostResponse,
+               _config: 'api_config.ApiConfig'):
   """Set the URI for a given binhost key and build target.
 
   See BinhostService documentation in api/proto/binhost.proto.
 
   Args:
-    input_proto (SetBinhostRequest): The input proto.
-    output_proto (SetBinhostResponse): The output proto.
-    _config (api_config.ApiConfig): The API call config.
+    input_proto: The input proto.
+    output_proto: The output proto.
+    _config: The API call config.
   """
   target = input_proto.build_target.name
   key = binhost_pb2.BinhostKey.Name(input_proto.key)
@@ -240,15 +251,17 @@
 @validate.require('overlay_type')
 @validate.is_in('overlay_type', _OVERLAY_TYPE_TO_NAME)
 @validate.validation_complete
-def RegenBuildCache(input_proto, output_proto, _config):
+def RegenBuildCache(input_proto: binhost_pb2.RegenBuildCacheRequest,
+                    output_proto: binhost_pb2.RegenBuildCacheResponse,
+                    _config: 'api_config.ApiConfig'):
   """Regenerate the Build Cache for a build target.
 
   See BinhostService documentation in api/proto/binhost.proto.
 
   Args:
-    input_proto (RegenBuildCacheRequest): The input proto.
-    output_proto (RegenBuildCacheResponse): The output proto.
-    _config (api_config.ApiConfig): The API call config.
+    input_proto: The input proto.
+    output_proto: The output proto.
+    _config: The API call config.
   """
   chroot = controller_util.ParseChroot(input_proto.chroot)
   overlay_type = input_proto.overlay_type
diff --git a/api/controller/controller_util.py b/api/controller/controller_util.py
index 9e769e4..3a3b9ea 100644
--- a/api/controller/controller_util.py
+++ b/api/controller/controller_util.py
@@ -3,17 +3,25 @@
 # found in the LICENSE file.
 
 """Utility functions that are useful for controllers."""
-import logging
 
-from chromite.api.gen.chromite.api import sysroot_pb2
+import glob
+import logging
+import os
+from typing import TYPE_CHECKING, Union
+
+from chromite.api.gen.chromite.api import sysroot_pb2, test_pb2
 from chromite.api.gen.chromiumos import common_pb2
 from chromite.cbuildbot import goma_util
 from chromite.lib import build_target_lib
 from chromite.lib import constants
 from chromite.lib.parser import package_info
 from chromite.lib import chroot_lib
+from chromite.lib import remoteexec_util
 from chromite.lib import sysroot_lib
 
+if TYPE_CHECKING:
+  from chromite.api.gen.chromiumos.build.api import portage_pb2
+
 class Error(Exception):
   """Base error class for the module."""
 
@@ -77,6 +85,18 @@
   return sysroot_lib.Sysroot(sysroot_message.path)
 
 
+def ParseRemoteexecConfig(remoteexec_message: common_pb2.RemoteexecConfig):
+  """Parse a remoteexec config message."""
+  assert isinstance(remoteexec_message, common_pb2.RemoteexecConfig)
+
+  if not (remoteexec_message.reclient_dir or
+          remoteexec_message.reproxy_cfg_file):
+    return None
+
+  return remoteexec_util.Remoteexec(remoteexec_message.reclient_dir,
+                                    remoteexec_message.reproxy_cfg_file)
+
+
 def ParseGomaConfig(goma_message, chroot_path):
   """Parse a goma config message."""
   assert isinstance(goma_message, common_pb2.GomaConfig)
@@ -147,7 +167,8 @@
 
 
 def serialize_package_info(pkg_info: package_info.PackageInfo,
-                           pkg_info_msg: common_pb2.PackageInfo):
+                           pkg_info_msg: Union[common_pb2.PackageInfo,
+                                               'portage_pb2.Portage.Package']):
   """Serialize a PackageInfo object to a PackageInfo proto."""
   if not isinstance(pkg_info, package_info.PackageInfo):
     # Allows us to swap everything to serialize_package_info, and search the
@@ -168,6 +189,44 @@
   return package_info.parse(PackageInfoToString(pkg_info_msg))
 
 
+def retrieve_package_log_paths(error: sysroot_lib.PackageInstallError,
+                               output_proto: Union[
+                                   sysroot_pb2.InstallPackagesResponse,
+                                   sysroot_pb2.InstallToolchainResponse,
+                                   test_pb2.BuildTargetUnitTestResponse
+                               ],
+                               target_sysroot: sysroot_lib.Sysroot) -> None:
+  """Get the path to the log file for each package that failed to build.
+
+  Args:
+    error: The error message produced by the build step.
+    output_proto: The Response message for a given API call. This response proto
+      must contain a failed_package_data field.
+    target_sysroot: The sysroot used by the build step.
+  """
+  for pkg_info in error.failed_packages:
+    # TODO(b/206514844): remove when field is deleted
+    package_info_msg = output_proto.failed_packages.add()
+    serialize_package_info(pkg_info, package_info_msg)
+    # Grab the paths to the log files for each failed package from the
+    # sysroot.
+    # Logs currently exist within the sysroot in the form of:
+    # /build/${BOARD}/tmp/portage/logs/$CATEGORY:$PF:$TIMESTAMP.log
+    failed_pkg_data_msg = output_proto.failed_package_data.add()
+    serialize_package_info(pkg_info, failed_pkg_data_msg.name)
+    glob_path = os.path.join(target_sysroot.portage_logdir,
+                             f'{pkg_info.category}:{pkg_info.pvr}:*.log')
+    log_files = glob.glob(glob_path)
+    log_files.sort(reverse=True)
+    # Omit path if files don't exist for some reason.
+    if not log_files:
+      logging.warning('Log file for %s was not found. Search path: %s',
+                      pkg_info.cpvr, glob_path)
+      continue
+    failed_pkg_data_msg.log_path.path = log_files[0]
+    failed_pkg_data_msg.log_path.location = common_pb2.Path.INSIDE
+
+
 def PackageInfoToCPV(package_info_msg):
   """Helper to translate a PackageInfo message into a CPV."""
   if not package_info_msg or not package_info_msg.package_name:
diff --git a/api/controller/controller_util_unittest.py b/api/controller/controller_util_unittest.py
index ac40548..def3080 100644
--- a/api/controller/controller_util_unittest.py
+++ b/api/controller/controller_util_unittest.py
@@ -9,10 +9,12 @@
 from chromite.api.gen.chromite.api import sysroot_pb2
 from chromite.api.gen.chromiumos import common_pb2
 from chromite.lib import build_target_lib
+from chromite.lib import cros_build_lib
 from chromite.lib import cros_test_lib
 from chromite.lib.parser import package_info
 from chromite.lib.chroot_lib import Chroot
 from chromite.lib.sysroot_lib import Sysroot
+from chromite.lib.sysroot_lib import PackageInstallError
 
 
 class ParseChrootTest(cros_test_lib.MockTestCase):
@@ -228,3 +230,17 @@
   pkg_info_msg.version = '1.2.3-r4'
   pkg_info = controller_util.deserialize_package_info(pkg_info_msg)
   assert pkg_info.cpvr == 'foo/bar-1.2.3-r4'
+
+
+def test_retrieve_package_log_paths():
+  error = PackageInstallError(
+      msg='Failed to install 3 packages',
+      result=cros_build_lib.CommandResult(),
+      packages=[package_info.parse('foo/bar%d-1.0-r1' % num)
+                for num in range(1, 4)])
+  output_proto = sysroot_pb2.InstallPackagesResponse()
+  target_sysroot = Sysroot(path='/path/to/sysroot')
+  controller_util.retrieve_package_log_paths(error,
+                                             output_proto,
+                                             target_sysroot)
+  assert len(output_proto.failed_package_data) == 3
diff --git a/api/controller/firmware.py b/api/controller/firmware.py
index e3cf931..f959d38 100644
--- a/api/controller/firmware.py
+++ b/api/controller/firmware.py
@@ -22,17 +22,28 @@
 from chromite.lib import cros_build_lib
 from chromite.lib import osutils
 
+def get_fw_loc(fw_loc):
+  """Get firmware_builder.py location.
+
+  Args:
+    fw_loc (enum): FwLocation enum.
+
+  Returns:
+    (str): path to firmware_builder.py for valid fw_loc.
+  """
+  return {
+      common_pb2.PLATFORM_EC: 'src/platform/ec/',
+      common_pb2.PLATFORM_ZEPHYR: 'src/platform/ec/zephyr/',
+      common_pb2.PLATFORM_TI50: 'src/platform/ti50/common/',
+      common_pb2.PLATFORM_CR50: 'src/platform/cr50/'
+  }.get(fw_loc, '')
+
 
 def _call_entry(fw_loc, metric_proto, subcmd, *args, **kwargs):
   """Calls into firmware_builder.py with the specified subcmd."""
 
-  if fw_loc == common_pb2.PLATFORM_EC:
-    fw_path = 'src/platform/ec/'
-  elif fw_loc == common_pb2.PLATFORM_ZEPHYR:
-    fw_path = 'src/platform/ec/zephyr/'
-  elif fw_loc == common_pb2.PLATFORM_TI50:
-    fw_path = 'src/platform/ti50/common/'
-  else:
+  fw_path = get_fw_loc(fw_loc)
+  if not fw_path:
     cros_build_lib.Die(f'Unknown firmware location {fw_loc}.')
 
   entry_point = os.path.join(constants.SOURCE_ROOT, fw_path,
diff --git a/api/controller/firmware_unittest.py b/api/controller/firmware_unittest.py
index 2f74b6a..adf8bf1 100644
--- a/api/controller/firmware_unittest.py
+++ b/api/controller/firmware_unittest.py
@@ -41,42 +41,58 @@
 
   def testBuildAllFirmware(self):
     """Test invocation of endpoint by verifying call to cros_build_lib.run."""
-    request = self._GetInput(chroot_path=self.chroot_path, code_coverage=True)
-    # TODO(mmortensen): Consider refactoring firmware._call_entry code (perhaps
-    # putting the parsing of the output file in a function) so that we don't
-    # have to mock something as generic as 'json_format.Parse' to avoid an
-    # error on parsing an empty(due to mock call) file.
-    json_format_patch = self.PatchObject(json_format, 'Parse')
-    response = firmware_pb2.BuildAllFirmwareResponse()
-    # Call the method under test.
-    firmware.BuildAllFirmware(request, response, self.api_config)
-    # Because we mock out the function, we verify that it is called as we
-    # expect it to be called.
-    called_function = os.path.join(constants.SOURCE_ROOT,
-                                   'src/platform/ec/firmware_builder.py')
-    self.cros_build_run_patch.assert_called_with(
-        [called_function, '--metrics', mock.ANY, '--code-coverage', 'build'],
-        check=False)
-    # Verify that we try to parse the metrics file.
-    json_format_patch.assert_called()
+    for fw_loc in common_pb2.FwLocation.values():
+      fw_path = firmware.get_fw_loc(fw_loc)
+      if not fw_path:
+        continue
+      request = self._GetInput(chroot_path=self.chroot_path,
+                               fw_location=fw_loc,
+                               code_coverage=True)
+      # TODO(mmortensen): Consider refactoring firmware._call_entry code
+      # (putting the parsing of the output file in a function) so that we don't
+      # have to mock something as generic as 'json_format.Parse' to avoid an
+      # error on parsing an empty(due to mock call) file.
+      json_format_patch = self.PatchObject(json_format, 'Parse')
+      response = firmware_pb2.BuildAllFirmwareResponse()
+      # Call the method under test.
+      firmware.BuildAllFirmware(request, response, self.api_config)
+      # Because we mock out the function, we verify that it is called as we
+      # expect it to be called.
+      called_function = os.path.join(constants.SOURCE_ROOT,
+                                     fw_path, 'firmware_builder.py')
+      self.cros_build_run_patch.assert_called_with(
+          [called_function, '--metrics', mock.ANY, '--code-coverage', 'build'],
+          check=False)
+      # Verify that we try to parse the metrics file.
+      json_format_patch.assert_called()
 
   def testValidateOnly(self):
     """Sanity check that a validate only call does not execute any logic."""
-    request = self._GetInput(chroot_path=self.chroot_path, code_coverage=True)
-    response = firmware_pb2.BuildAllFirmwareResponse()
-    firmware.BuildAllFirmware(request, response, self.validate_only_config)
-    self.cros_build_run_patch.assert_not_called()
+    for fw_loc in common_pb2.FwLocation.values():
+      if not firmware.get_fw_loc(fw_loc):
+        continue
+      request = self._GetInput(chroot_path=self.chroot_path,
+                               fw_location=fw_loc,
+                               code_coverage=True)
+      response = firmware_pb2.BuildAllFirmwareResponse()
+      firmware.BuildAllFirmware(request, response, self.validate_only_config)
+      self.cros_build_run_patch.assert_not_called()
 
   def testMockCall(self):
     """Test that a mock call does not execute logic, returns mocked value."""
-    request = self._GetInput(chroot_path=self.chroot_path, code_coverage=True)
-    response = firmware_pb2.BuildAllFirmwareResponse()
-    firmware.BuildAllFirmware(request, response, self.mock_call_config)
-    self.cros_build_run_patch.assert_not_called()
-    self.assertEqual(len(response.metrics.value), 1)
-    self.assertEqual(response.metrics.value[0].target_name, 'foo')
-    self.assertEqual(response.metrics.value[0].platform_name, 'bar')
-    self.assertEqual(len(response.metrics.value[0].fw_section), 1)
-    self.assertEqual(response.metrics.value[0].fw_section[0].region, 'EC_RO')
-    self.assertEqual(response.metrics.value[0].fw_section[0].used, 100)
-    self.assertEqual(response.metrics.value[0].fw_section[0].total, 150)
+    for fw_loc in common_pb2.FwLocation.values():
+      if not firmware.get_fw_loc(fw_loc):
+        continue
+      request = self._GetInput(chroot_path=self.chroot_path,
+                               fw_location=fw_loc,
+                               code_coverage=True)
+      response = firmware_pb2.BuildAllFirmwareResponse()
+      firmware.BuildAllFirmware(request, response, self.mock_call_config)
+      self.cros_build_run_patch.assert_not_called()
+      self.assertEqual(len(response.metrics.value), 1)
+      self.assertEqual(response.metrics.value[0].target_name, 'foo')
+      self.assertEqual(response.metrics.value[0].platform_name, 'bar')
+      self.assertEqual(len(response.metrics.value[0].fw_section), 1)
+      self.assertEqual(response.metrics.value[0].fw_section[0].region, 'EC_RO')
+      self.assertEqual(response.metrics.value[0].fw_section[0].used, 100)
+      self.assertEqual(response.metrics.value[0].fw_section[0].total, 150)
diff --git a/api/controller/image.py b/api/controller/image.py
index a0609ac..2de6e83 100644
--- a/api/controller/image.py
+++ b/api/controller/image.py
@@ -79,6 +79,7 @@
     common_pb2.IMAGE_TYPE_FIRMWARE: constants.IMAGE_TYPE_FIRMWARE,
     common_pb2.IMAGE_TYPE_ACCESSORY_USBPD: constants.IMAGE_TYPE_ACCESSORY_USBPD,
     common_pb2.IMAGE_TYPE_ACCESSORY_RWSIG: constants.IMAGE_TYPE_ACCESSORY_RWSIG,
+    common_pb2.IMAGE_TYPE_HPS_FIRMWARE: constants.IMAGE_TYPE_HPS_FIRMWARE,
     common_pb2.IMAGE_TYPE_BASE: constants.IMAGE_TYPE_BASE,
     common_pb2.IMAGE_TYPE_GSC_FIRMWARE: constants.IMAGE_TYPE_GSC_FIRMWARE,
 }
@@ -464,13 +465,16 @@
         for channel in input_proto.channels
     ]
   try:
-    pushimage.PushImage(
+    channel_to_uris = pushimage.PushImage(
         input_proto.gs_image_dir,
         input_proto.sysroot.build_target.name,
         dry_run=input_proto.dryrun,
         sign_types=sign_types,
         **kwargs)
-    return controller.RETURN_CODE_SUCCESS
   except Exception:
     logging.error('PushImage failed: ', exc_info=True)
     return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
+  for uris in channel_to_uris.values():
+    for uri in uris:
+      _output_proto.instructions.add().instructions_file_path = uri
+  return controller.RETURN_CODE_SUCCESS
diff --git a/api/controller/image_unittest.py b/api/controller/image_unittest.py
index 97b01d8..ceff870 100644
--- a/api/controller/image_unittest.py
+++ b/api/controller/image_unittest.py
@@ -345,12 +345,9 @@
     self.assertFalse(output_proto.success)
 
 
-class PushImageTest(cros_test_lib.MockTestCase, api_config.ApiConfigMixin):
+class PushImageTest(api_config.ApiConfigMixin):
   """Push image test."""
 
-  def setUp(self):
-    self.response = image_pb2.PushImageResponse()
-
   def _GetRequest(
       self,
       gs_image_dir='gs://chromeos-image-archive/atlas-release/R89-13604.0.0',
@@ -368,76 +365,72 @@
         dryrun=dryrun,
         channels=channels)
 
-  def testValidateOnly(self):
-    """Check that a validate only call does not execute any logic."""
-    patch = self.PatchObject(pushimage, 'PushImage')
+  def _GetResponse(self):
+    return image_pb2.PushImageRequest()
 
+  @mock.patch.object(pushimage, 'PushImage', return_value={})
+  def testValidateOnly(self, MockPushImage):
+    """Check that a validate only call does not execute any logic."""
     req = self._GetRequest(sign_types=[
         common_pb2.IMAGE_TYPE_RECOVERY, common_pb2.IMAGE_TYPE_FACTORY,
         common_pb2.IMAGE_TYPE_FIRMWARE, common_pb2.IMAGE_TYPE_ACCESSORY_USBPD,
         common_pb2.IMAGE_TYPE_ACCESSORY_RWSIG, common_pb2.IMAGE_TYPE_BASE,
-        common_pb2.IMAGE_TYPE_GSC_FIRMWARE
+        common_pb2.IMAGE_TYPE_GSC_FIRMWARE, common_pb2.IMAGE_TYPE_HPS_FIRMWARE,
     ])
-    res = image_controller.PushImage(req, self.response,
-                                     self.validate_only_config)
-    patch.assert_not_called()
-    self.assertEqual(res, controller.RETURN_CODE_VALID_INPUT)
+    rc = image_controller.PushImage(req, self.NewResponse(),
+                                    self.validate_only_config)
+    MockPushImage.assert_not_called()
+    self.assertEqual(rc, controller.RETURN_CODE_VALID_INPUT)
 
-  def testValidateOnlyInvalid(self):
+  @mock.patch.object(pushimage, 'PushImage', return_value={})
+  def testValidateOnlyInvalid(self, MockPushImage):
     """Check that validate call rejects invalid sign types."""
-    patch = self.PatchObject(pushimage, 'PushImage')
-
     # Pass unsupported image type.
     req = self._GetRequest(sign_types=[common_pb2.IMAGE_TYPE_DLC])
-    res = image_controller.PushImage(req, self.response,
-                                     self.validate_only_config)
-    patch.assert_not_called()
-    self.assertEqual(res, controller.RETURN_CODE_INVALID_INPUT)
+    rc = image_controller.PushImage(req, self._GetResponse(),
+                                    self.validate_only_config)
+    MockPushImage.assert_not_called()
+    self.assertEqual(rc, controller.RETURN_CODE_INVALID_INPUT)
 
-  def testMockCall(self):
+  @mock.patch.object(pushimage, 'PushImage', return_value={})
+  def testMockCall(self, MockPushImage):
     """Test that mock call does not execute any logic, returns mocked value."""
-    patch = self.PatchObject(pushimage, 'PushImage')
-
-    rc = image_controller.PushImage(self._GetRequest(), self.response,
+    rc = image_controller.PushImage(self._GetRequest(), self._GetResponse(),
                                     self.mock_call_config)
-    patch.assert_not_called()
+    MockPushImage.assert_not_called()
     self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
 
-  def testMockError(self):
+  @mock.patch.object(pushimage, 'PushImage', return_value={})
+  def testMockError(self, MockPushImage):
     """Test that mock call does not execute any logic, returns error."""
-    patch = self.PatchObject(pushimage, 'PushImage')
-
-    rc = image_controller.PushImage(self._GetRequest(), self.response,
+    rc = image_controller.PushImage(self._GetRequest(), self._GetResponse(),
                                     self.mock_error_config)
-    patch.assert_not_called()
+    MockPushImage.assert_not_called()
     self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
 
-  def testNoBuildTarget(self):
+  @mock.patch.object(pushimage, 'PushImage', return_value={})
+  def testNoBuildTarget(self, _):
     """Test no build target given fails."""
     request = self._GetRequest(build_target_name='')
-
-    # No build target should cause it to fail.
     with self.assertRaises(cros_build_lib.DieSystemExit):
-      image_controller.PushImage(request, self.response, self.api_config)
+      image_controller.PushImage(request, self._GetResponse(), self.api_config)
 
-  def testNoGsImageDir(self):
+  @mock.patch.object(pushimage, 'PushImage', return_value={})
+  def testNoGsImageDir(self, _):
     """Test no image dir given fails."""
     request = self._GetRequest(gs_image_dir='')
-
-    # No image dir should cause it to fail.
     with self.assertRaises(cros_build_lib.DieSystemExit):
-      image_controller.PushImage(request, self.response, self.api_config)
+      image_controller.PushImage(request, self._GetResponse(), self.api_config)
 
-  def testCallCorrect(self):
+  @mock.patch.object(pushimage, 'PushImage', return_value={})
+  def testCallCorrect(self, MockPushImage):
     """Check that a call is called with the correct parameters."""
-    patch = self.PatchObject(pushimage, 'PushImage')
-
     request = self._GetRequest(
         dryrun=False, profile='', sign_types=[common_pb2.IMAGE_TYPE_RECOVERY],
         channels=[common_pb2.CHANNEL_DEV, common_pb2.CHANNEL_CANARY])
     request.dest_bucket = 'gs://foo'
-    image_controller.PushImage(request, self.response, self.api_config)
-    patch.assert_called_with(
+    image_controller.PushImage(request, self._GetResponse(), self.api_config)
+    MockPushImage.assert_called_with(
         request.gs_image_dir,
         request.sysroot.build_target.name,
         dry_run=request.dryrun,
@@ -445,14 +438,32 @@
         dest_bucket=request.dest_bucket,
         force_channels=['dev', 'canary'])
 
-  def testCallSucceeds(self):
+  @mock.patch.object(pushimage, 'PushImage', return_value={
+      'dev': ['gs://dev/instr1', 'gs://dev/instr2'],
+      'canary': ['gs://canary/instr1']})
+  def testOutput(self, _):
+    """Check that a call populates the response object."""
+    request = self._GetRequest(
+        profile='', sign_types=[common_pb2.IMAGE_TYPE_RECOVERY],
+        channels=[common_pb2.CHANNEL_DEV, common_pb2.CHANNEL_CANARY])
+    request.dest_bucket = 'gs://foo'
+    response = self._GetResponse()
+    image_controller.PushImage(request, response, self.api_config)
+    self.assertEqual(
+        sorted([i.instructions_file_path for i in response.instructions]),
+        sorted(['gs://dev/instr1', 'gs://dev/instr2', 'gs://canary/instr1']))
+
+  def testCallSucceeds(self, _):
     """Check that a (dry run) call is made successfully."""
     request = self._GetRequest(sign_types=[common_pb2.IMAGE_TYPE_RECOVERY])
-    res = image_controller.PushImage(request, self.response, self.api_config)
-    self.assertEqual(res, controller.RETURN_CODE_SUCCESS)
+    rc = image_controller.PushImage(
+        request,
+        self._GetResponse(),
+        self.api_config)
+    self.assertEqual(rc, controller.RETURN_CODE_SUCCESS)
 
   def testCallFailsWithBadImageDir(self):
     """Check that a (dry run) call fails when given a bad gs_image_dir."""
     request = self._GetRequest(gs_image_dir='foo')
-    res = image_controller.PushImage(request, self.response, self.api_config)
-    self.assertEqual(res, controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY)
+    rc = image_controller.PushImage(request, self._GetResponse, self.api_config)
+    self.assertEqual(rc, controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY)
diff --git a/api/controller/metadata.py b/api/controller/metadata.py
new file mode 100644
index 0000000..c5c8086
--- /dev/null
+++ b/api/controller/metadata.py
@@ -0,0 +1,82 @@
+# Copyright 2022 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Build metadata operations."""
+
+from chromite.api import faux
+from chromite.api import validate
+from chromite.api.controller import controller_util
+from chromite.api.gen.chromiumos.build.api import portage_pb2
+from chromite.api.gen.chromiumos.build.api import system_image_pb2
+from chromite.lib.parser import package_info
+
+from chromite.lib import portage_util
+from chromite.service import packages
+
+
+def _SystemImageMetadataResponse(_input_proto, output_proto, _config):
+  response = system_image_pb2.SystemImage()
+  portage_build_target = portage_pb2.Portage.BuildTarget(
+      overlay_name='overlay-build-target',
+      profile_name='base',
+      use_flags=['use', 'flag'],
+      features=['feature'],
+  )
+
+  BuildMetadata = system_image_pb2.SystemImage.BuildMetadata
+  package_summary = BuildMetadata.PackageSummary(
+      arc=BuildMetadata.Arc(version='1.2.3', branch='mock'),
+      chrome=BuildMetadata.AshChrome(version='1.2.3.4'),
+      chipset=BuildMetadata.Chipset(overlay='mock'),
+      kernel=BuildMetadata.Kernel(version='1.2'),
+      toolchain=BuildMetadata.Toolchain(version=None),
+  )
+
+  output_proto.metadata.build_target = portage_build_target
+  output_proto.metadata.package_summary = package_summary
+  for cpvr in ['cat/pkg-1.2.3-r4', 'foo/bar-5.6.7-r8']:
+    pkg = package_info.parse(cpvr)
+    msg = output_proto.metadata.packages.add()
+    controller_util.serialize_package_info(pkg, msg)
+
+  return response
+
+
+@faux.success(_SystemImageMetadataResponse)
+@faux.empty_error
+@validate.exists('sysroot.path')
+@validate.require('sysroot.build_target.name')
+@validate.validation_complete
+def SystemImageMetadata(input_proto, output_proto, _config):
+  sysroot = controller_util.ParseSysroot(input_proto.sysroot)
+  build_target = controller_util.ParseBuildTarget(
+      input_proto.sysroot.build_target)
+
+  portage_build_target = portage_pb2.Portage.BuildTarget(
+      overlay_name=getattr(sysroot.build_target_overlay, 'name', ''),
+      profile_name=sysroot.profile_name,
+      use_flags=sysroot.use_flags,
+      features=sysroot.features,
+  )
+
+  target_versions = packages.get_target_versions(build_target)
+  BuildMetadata = system_image_pb2.SystemImage.BuildMetadata
+  package_summary = BuildMetadata.PackageSummary(
+      arc=BuildMetadata.Arc(
+          version=target_versions.android_version,
+          branch=target_versions.android_branch),
+      chrome=BuildMetadata.AshChrome(version=target_versions.chrome_version),
+      chipset=BuildMetadata.Chipset(overlay=sysroot.chipset or ''),
+      kernel=BuildMetadata.Kernel(
+          version=packages.determine_kernel_version(build_target) or ''),
+  )
+
+  output_proto.system_image.metadata.build_target.portage_build_target.CopyFrom(
+      portage_build_target)
+  output_proto.system_image.metadata.package_summary.CopyFrom(package_summary)
+
+  portage_db = portage_util.PortageDB(sysroot.path)
+  for pkg in portage_db.InstalledPackages():
+    msg = output_proto.system_image.metadata.packages.add()
+    controller_util.serialize_package_info(pkg.package_info, msg)
diff --git a/api/controller/packages.py b/api/controller/packages.py
index 2a98e47..a9f98ae 100644
--- a/api/controller/packages.py
+++ b/api/controller/packages.py
@@ -89,9 +89,18 @@
     # Handle module errors nicely, let everything else bubble up.
     cros_build_lib.Die(e)
 
-  if not result.uprevved:
-    # No uprevs executed, skip the output population.
-    return
+  for modified in result.modified:
+    uprev_response = output_proto.responses.add()
+    uprev_response.version = modified.new_version
+    for path in modified.files:
+      uprev_response.modified_ebuilds.add().path = path
+
+
+@faux.success(_UprevVersionedPackageResponse)
+@faux.empty_error
+@validate.validation_complete
+def RevBumpChrome(_input_proto, output_proto, _config):
+  result = packages.revbump_chrome()
 
   for modified in result.modified:
     uprev_response = output_proto.responses.add()
@@ -160,51 +169,18 @@
 def GetTargetVersions(input_proto, output_proto, _config):
   """Returns the target versions."""
   build_target = controller_util.ParseBuildTarget(input_proto.build_target)
-  # Look up the android package here once since the operation is so slow.
-  android_package = packages.determine_android_package(build_target.name)
-  if android_package:
-    # Android version.
-    android_version = packages.determine_android_version(
-        build_target.name, package=android_package)
-    logging.info('Found android version: %s', android_version)
-    if android_version:
-      output_proto.android_version = android_version
-    # Android branch version.
-    android_branch_version = packages.determine_android_branch(
-        build_target.name, package=android_package)
-    logging.info('Found android branch version: %s', android_branch_version)
-    if android_branch_version:
-      output_proto.android_branch_version = android_branch_version
-    # Android target version.
-    android_target_version = packages.determine_android_target(
-        build_target.name, package=android_package)
-    logging.info('Found android target version: %s', android_target_version)
-    if android_target_version:
-      output_proto.android_target_version = android_target_version
+  package_list = [
+      controller_util.PackageInfoToCPV(x) for x in input_proto.packages or []
+  ]
+  target_versions = packages.get_target_versions(build_target, package_list)
 
-  # TODO(crbug/1019770): Investigate cases where builds_chrome is true but
-  # chrome_version is None.
-
-  # If input_proto.packages is empty, then the default set of packages will
-  # be used as defined in dependency.GetBuildDependency.
-  package_list = None
-  if input_proto.packages:
-    package_list = [
-        controller_util.PackageInfoToCPV(x) for x in input_proto.packages
-    ]
-  builds_chrome = packages.builds(constants.CHROME_CP, build_target,
-                                  packages=package_list)
-  if builds_chrome:
-    # Chrome version fetch.
-    chrome_version = packages.determine_chrome_version(build_target)
-    logging.info('Found chrome version: %s', chrome_version)
-    if chrome_version:
-      output_proto.chrome_version = chrome_version
-
-  # The ChromeOS version info.
-  output_proto.platform_version = packages.determine_platform_version()
-  output_proto.milestone_version = packages.determine_milestone_version()
-  output_proto.full_version = packages.determine_full_version()
+  output_proto.android_version = target_versions.android_version or ''
+  output_proto.android_branch_version = target_versions.android_branch or ''
+  output_proto.android_target_version = target_versions.android_target or ''
+  output_proto.chrome_version = target_versions.chrome_version or ''
+  output_proto.platform_version = target_versions.platform_version or ''
+  output_proto.milestone_version = target_versions.milestone_version or ''
+  output_proto.full_version = target_versions.full_version or ''
 
 
 def _GetBuilderMetadataResponse(input_proto, output_proto, _config):
@@ -247,8 +223,10 @@
       build_target.name)
 
   fw_versions = packages.determine_firmware_versions(build_target)
-  build_target_metadata.main_firmware_version = fw_versions.main_fw_version
-  build_target_metadata.ec_firmware_version = fw_versions.ec_fw_version
+  if fw_versions:
+    build_target_metadata.main_firmware_version = fw_versions.main_fw_version
+    build_target_metadata.ec_firmware_version = fw_versions.ec_fw_version
+
   build_target_metadata.kernel_version = packages.determine_kernel_version(
       build_target)
   fingerprints = packages.find_fingerprints(build_target)
diff --git a/api/controller/packages_unittest.py b/api/controller/packages_unittest.py
index 7834b24..42c8434 100644
--- a/api/controller/packages_unittest.py
+++ b/api/controller/packages_unittest.py
@@ -324,67 +324,23 @@
     return request
 
   def testValidateOnly(self):
-    """Sanity check that a validate only call does not execute any logic."""
-    builds_chrome = self.PatchObject(
-        packages_service, 'builds', return_value=True)
-    patch_version = self.PatchObject(packages_service,
-                                     'determine_android_version')
-    patch_branch_version = self.PatchObject(packages_service,
-                                            'determine_android_branch')
-    patch_target_version = self.PatchObject(packages_service,
-                                            'determine_android_target')
-    chrome_version = self.PatchObject(packages_service,
-                                      'determine_chrome_version')
-    platform_version = self.PatchObject(packages_service,
-                                        'determine_platform_version')
-    milestone_version = self.PatchObject(packages_service,
-                                         'determine_milestone_version')
-    full_version = self.PatchObject(packages_service,
-                                    'determine_full_version')
+    """Quick check that a validate only call does not execute any logic."""
+    patch_version = self.PatchObject(packages_service, 'get_target_versions')
 
     request = self._GetRequest(board='betty')
     packages_controller.GetTargetVersions(request, self.response,
                                           self.validate_only_config)
     patch_version.assert_not_called()
-    patch_branch_version.assert_not_called()
-    patch_target_version.assert_not_called()
-    builds_chrome.assert_not_called()
-    chrome_version.assert_not_called()
-    platform_version.assert_not_called()
-    milestone_version.assert_not_called()
-    full_version.assert_not_called()
 
   def testMockCall(self):
     """Test that a mock call does not execute logic, returns mocked value."""
-    builds_chrome = self.PatchObject(
-        packages_service, 'builds', return_value=True)
-    patch_version = self.PatchObject(packages_service,
-                                     'determine_android_version')
-    patch_branch_version = self.PatchObject(packages_service,
-                                            'determine_android_branch')
-    patch_target_version = self.PatchObject(packages_service,
-                                            'determine_android_target')
-    chrome_version = self.PatchObject(packages_service,
-                                      'determine_chrome_version')
-    platform_version = self.PatchObject(packages_service,
-                                        'determine_platform_version')
-    milestone_version = self.PatchObject(packages_service,
-                                         'determine_milestone_version')
-    full_version = self.PatchObject(packages_service,
-                                    'determine_full_version')
+    patch_version = self.PatchObject(packages_service, 'get_target_versions')
 
     request = self._GetRequest(board='betty')
     packages_controller.GetTargetVersions(request, self.response,
                                           self.mock_call_config)
 
     patch_version.assert_not_called()
-    patch_branch_version.assert_not_called()
-    patch_target_version.assert_not_called()
-    builds_chrome.assert_not_called()
-    chrome_version.assert_not_called()
-    platform_version.assert_not_called()
-    milestone_version.assert_not_called()
-    full_version.assert_not_called()
 
     self.assertTrue(self.response.android_version)
     self.assertTrue(self.response.android_branch_version)
@@ -414,9 +370,10 @@
     self.PatchObject(packages_service, 'determine_android_package',
                      return_value=android_package)
     android_branch = 'android_test_branch'
-    android_branch_mock = self.PatchObject(packages_service,
-                                           'determine_android_branch',
-                                           return_value=android_branch)
+    android_branch_mock = self.PatchObject(
+        packages_service,
+        'determine_android_branch',
+        return_value=android_branch)
     platform_version = '12345.1.2'
     self.PatchObject(packages_service, 'determine_platform_version',
                      return_value=platform_version)
@@ -440,7 +397,7 @@
     build_target = build_target_lib.BuildTarget('betty')
     chrome_version_mock.assert_called_with(build_target)
     # Verify call to determine_android_branch passes a board name.
-    android_branch_mock.assert_called_with('betty', package=android_package)
+    android_branch_mock.assert_called_with('betty')
 
   def testGetTargetVersionsWithPackagesSet(self):
     """Verify packages pass through and basic return values."""
diff --git a/api/controller/payload.py b/api/controller/payload.py
index 00d5cf1..c1b9042 100644
--- a/api/controller/payload.py
+++ b/api/controller/payload.py
@@ -5,9 +5,11 @@
 """Payload API Service."""
 
 from chromite.api import controller
-from chromite.lib import cros_build_lib
 from chromite.api import faux
 from chromite.api import validate
+from chromite.api.gen.chromite.api import payload_pb2
+from chromite.lib import cros_build_lib
+from chromite.lib.paygen import paygen_payload_lib
 from chromite.service import payload
 
 
@@ -17,6 +19,10 @@
                       ('full_update', 'tgt_unsigned_image'),
                       ('full_update', 'tgt_signed_image'),
                       ('full_update', 'tgt_dlc_image'))
+_VALID_MINIOS_PAIRS = (('src_signed_image', 'tgt_signed_image'),
+                       ('src_unsigned_image', 'tgt_unsigned_image'),
+                       ('full_update', 'tgt_unsigned_image'),
+                       ('full_update', 'tgt_signed_image'))
 
 _DEFAULT_PAYGEN_CACHE_DIR = '.paygen_cache'
 
@@ -63,21 +69,20 @@
     cros_build_lib.Die('%s and %s are not valid image pairs' %
                        (src_image, tgt_image))
 
+  # Ensure that miniOS payloads are only requested for compatible image types.
+  if input_proto.minios and (src_name, tgt_name) not in _VALID_MINIOS_PAIRS:
+    cros_build_lib.Die('%s and %s are not valid image pairs for miniOS' %
+                       (src_image, tgt_image))
+
   # Find the value of bucket or default to 'chromeos-releases'.
   destination_bucket = input_proto.bucket or 'chromeos-releases'
 
-  if input_proto.dryrun:
-    keyset = ''
-    upload = False
-  else:
-    keyset = input_proto.keyset
-    upload = True
-
   # There's a potential that some paygen_lib library might raise here, but since
   # we're still involved in config we'll keep it before the validate_only.
   payload_config = payload.PayloadConfig(tgt_image, src_image,
-                                         destination_bucket, input_proto.verify,
-                                         keyset, upload,
+                                         destination_bucket, input_proto.minios,
+                                         input_proto.verify,
+                                         upload=not input_proto.dryrun,
                                          cache_dir=_DEFAULT_PAYGEN_CACHE_DIR)
 
   # If configured for validation only we're done here.
@@ -85,10 +90,17 @@
     return controller.RETURN_CODE_VALID_INPUT
 
   # Do payload generation.
-  local_path, remote_uri = payload_config.GeneratePayload()
-  _SetGeneratePayloadOutputProto(output_proto, local_path, remote_uri)
+  local_path, remote_uri = '', ''
+  try:
+    local_path, remote_uri = payload_config.GeneratePayload()
+  except paygen_payload_lib.PayloadGenerationSkippedException as e:
+    # If paygen was skipped, provide a reason if possible.
+    if isinstance(e, paygen_payload_lib.NoMiniOSPartitionException):
+      reason = payload_pb2.GenerationResponse.NOT_MINIOS_COMPATIBLE
+      output_proto.failure_reason = reason
 
-  if remote_uri or not upload and local_path:
+  _SetGeneratePayloadOutputProto(output_proto, local_path, remote_uri)
+  if remote_uri or input_proto.dryrun and local_path:
     return controller.RETURN_CODE_SUCCESS
   else:
     return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
diff --git a/api/controller/payload_unittest.py b/api/controller/payload_unittest.py
index 217facc..b1c260c 100644
--- a/api/controller/payload_unittest.py
+++ b/api/controller/payload_unittest.py
@@ -41,13 +41,22 @@
         keyset='update_signer',
         dryrun=False)
 
+    self.minios_req = payload_pb2.GenerationRequest(
+        tgt_unsigned_image=tgt_image,
+        src_unsigned_image=src_image,
+        bucket='test-destination-bucket',
+        minios=True,
+        verify=True,
+        keyset='update_signer',
+        dryrun=False)
+
     self.result = payload_pb2.GenerationResponse(
         success=True,
         local_path='/tmp/aohiwdadoi/delta.bin',
         remote_uri='gs://something')
 
   def testValidateOnly(self):
-    """Sanity check that a validate only call does not execute any logic."""
+    """Basic check that a validate only call does not execute any logic."""
 
     res = payload.GeneratePayload(self.req, self.result,
                                   self.validate_only_config)
@@ -78,3 +87,18 @@
                                   self.mock_call_config)
     patch.assert_not_called()
     self.assertEqual(controller.RETURN_CODE_SUCCESS, res)
+
+  def testMiniOSSuccess(self):
+    """Test a miniOS paygen request."""
+    patch = self.PatchObject(paygen_payload_lib, 'PaygenPayload')
+    patch.return_value.Run.return_value = 'gs://minios/something'
+    res = payload.GeneratePayload(self.minios_req, self.result, self.api_config)
+    self.assertEqual(res, controller.RETURN_CODE_SUCCESS)
+
+  def testNoMiniOSPartition(self):
+    """Test a miniOS paygen request on an image with no miniOS part."""
+    patch = self.PatchObject(paygen_payload_lib, 'PaygenPayload')
+    patch.side_effect = paygen_payload_lib.NoMiniOSPartitionException
+    payload.GeneratePayload(self.minios_req, self.result, self.api_config)
+    self.assertEqual(self.result.failure_reason,
+                     payload_pb2.GenerationResponse.NOT_MINIOS_COMPATIBLE)
diff --git a/api/controller/sdk.py b/api/controller/sdk.py
index 37d3919..160ba88 100644
--- a/api/controller/sdk.py
+++ b/api/controller/sdk.py
@@ -35,6 +35,7 @@
 
   chroot_path = input_proto.chroot.path
   cache_dir = input_proto.chroot.cache_dir
+  sdk_version = input_proto.sdk_version
 
   if chroot_path and not os.path.isabs(chroot_path):
     cros_build_lib.Die('The chroot path must be absolute.')
@@ -47,7 +48,8 @@
       bootstrap=bootstrap,
       use_image=use_image,
       cache_dir=cache_dir,
-      chroot_path=chroot_path)
+      chroot_path=chroot_path,
+      sdk_version=sdk_version)
 
   version = sdk.Create(args)
 
@@ -119,7 +121,7 @@
 def Clean(input_proto, _output_proto, _config):
   """Clean unneeded files from a chroot."""
   chroot = controller_util.ParseChroot(input_proto.chroot)
-  sdk.Clean(chroot, images=True, sysroots=True, tmp=True)
+  sdk.Clean(chroot, safe=True, sysroots=True)
 
 
 @faux.all_empty
diff --git a/api/controller/sdk_unittest.py b/api/controller/sdk_unittest.py
index 9eebbd6..1ccca41 100644
--- a/api/controller/sdk_unittest.py
+++ b/api/controller/sdk_unittest.py
@@ -24,7 +24,7 @@
     self.response = sdk_pb2.CreateResponse()
 
   def _GetRequest(self, no_replace=False, bootstrap=False, no_use_image=False,
-                  cache_path=None, chroot_path=None):
+                  cache_path=None, chroot_path=None, sdk_version=None):
     """Helper to build a create request message."""
     request = sdk_pb2.CreateRequest()
     request.flags.no_replace = no_replace
@@ -35,6 +35,8 @@
       request.chroot.cache_dir = cache_path
     if chroot_path:
       request.chroot.path = chroot_path
+    if sdk_version:
+      request.sdk_version = sdk_version
 
     return request
 
@@ -82,7 +84,8 @@
         bootstrap=False,
         use_image=True,
         chroot_path=mock.ANY,
-        cache_dir=mock.ANY)
+        cache_dir=mock.ANY,
+        sdk_version=mock.ANY)
 
   def testTrueArguments(self):
     """Test True arguments handling."""
@@ -92,14 +95,15 @@
 
     # Test all True values in the message.
     request = self._GetRequest(no_replace=True, bootstrap=True,
-                               no_use_image=True)
+                               no_use_image=True, sdk_version='foo')
     sdk_controller.Create(request, self.response, self.api_config)
     args_patch.assert_called_with(
         replace=False,
         bootstrap=True,
         use_image=False,
         chroot_path=mock.ANY,
-        cache_dir=mock.ANY)
+        cache_dir=mock.ANY,
+        sdk_version='foo')
 
 
 class SdkDeleteTest(cros_test_lib.MockTestCase, api_config.ApiConfigMixin):
diff --git a/api/controller/sysroot.py b/api/controller/sysroot.py
index ec89c34..04cddc4 100644
--- a/api/controller/sysroot.py
+++ b/api/controller/sysroot.py
@@ -33,7 +33,7 @@
   uabs = common_pb2.UploadedArtifactsByService
   cabs = common_pb2.ArtifactsByService
   return uabs.Sysroot(artifacts=[
-     uabs.Sysroot.ArtifactPaths(
+      uabs.Sysroot.ArtifactPaths(
           artifact_type=cabs.Sysroot.ArtifactType.SIMPLE_CHROME_SYSROOT,
           paths=[
               common_pb2.Path(
@@ -59,8 +59,9 @@
 
 
 def GetArtifacts(in_proto: common_pb2.ArtifactsByService.Sysroot,
-        chroot: chroot_lib.Chroot, sysroot_class: sysroot_lib.Sysroot,
-        build_target: build_target_lib.BuildTarget, output_dir: str) -> list:
+                 chroot: chroot_lib.Chroot, sysroot_class: sysroot_lib.Sysroot,
+                 build_target: build_target_lib.BuildTarget, output_dir: str
+                 ) -> list:
   """Builds and copies sysroot artifacts to specified output_dir.
 
   Copies sysroot artifacts to output_dir, returning a list of (output_dir: str)
@@ -78,11 +79,12 @@
   """
   generated = []
   artifact_types = {
-    in_proto.ArtifactType.SIMPLE_CHROME_SYSROOT:
-        sysroot.CreateSimpleChromeSysroot,
-    in_proto.ArtifactType.CHROME_EBUILD_ENV: sysroot.CreateChromeEbuildEnv,
-    in_proto.ArtifactType.BREAKPAD_DEBUG_SYMBOLS: sysroot.BundleBreakpadSymbols,
-    in_proto.ArtifactType.DEBUG_SYMBOLS: sysroot.BundleDebugSymbols,
+      in_proto.ArtifactType.SIMPLE_CHROME_SYSROOT:
+          sysroot.CreateSimpleChromeSysroot,
+      in_proto.ArtifactType.CHROME_EBUILD_ENV: sysroot.CreateChromeEbuildEnv,
+      in_proto.ArtifactType.BREAKPAD_DEBUG_SYMBOLS:
+          sysroot.BundleBreakpadSymbols,
+      in_proto.ArtifactType.DEBUG_SYMBOLS: sysroot.BundleDebugSymbols,
   }
 
   for output_artifact in in_proto.output_artifacts:
@@ -162,6 +164,20 @@
   pkg2.category = 'foo'
   pkg2.version = '3.7-r99'
 
+  fail = output_proto.failed_package_data.add()
+  fail.name.package_name = 'package'
+  fail.name.category = 'category'
+  fail.name.version = '1.0.0_rc-r1'
+  fail.log_path.path = '/path/to/package:category-1.0.0_rc-r1:20210609-1337.log'
+  fail.log_path.location = common_pb2.Path.INSIDE
+
+  fail2 = output_proto.failed_package_data.add()
+  fail2.name.package_name = 'bar'
+  fail2.name.category = 'foo'
+  fail2.name.version = '3.7-r99'
+  fail2.log_path.path = '/path/to/foo:bar-3.7-r99:20210609-1620.log'
+  fail2.log_path.location = common_pb2.Path.INSIDE
+
 
 @faux.empty_success
 @faux.error(_MockFailedPackagesResponse)
@@ -185,10 +201,7 @@
   try:
     sysroot.InstallToolchain(build_target, target_sysroot, run_configs)
   except sysroot_lib.ToolchainInstallError as e:
-    # Error installing - populate the failed package info.
-    for pkg_info in e.failed_toolchain_info:
-      package_info_msg = output_proto.failed_packages.add()
-      controller_util.serialize_package_info(pkg_info, package_info_msg)
+    controller_util.retrieve_package_log_paths(e, output_proto, target_sysroot)
 
     return controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE
 
@@ -207,8 +220,12 @@
   """Install packages into a sysroot, building as necessary and permitted."""
   compile_source = (
       input_proto.flags.compile_source or input_proto.flags.toolchain_changed)
+
+  use_remoteexec = bool(input_proto.remoteexec_config.reproxy_cfg_file and
+                        input_proto.remoteexec_config.reclient_dir)
+
   # Testing if Goma will support unknown compilers now.
-  use_goma = input_proto.flags.use_goma
+  use_goma = input_proto.flags.use_goma and not use_remoteexec
 
   target_sysroot = sysroot_lib.Sysroot(input_proto.sysroot.path)
   build_target = controller_util.ParseBuildTarget(
@@ -240,6 +257,7 @@
       package_indexes=package_indexes,
       use_flags=use_flags,
       use_goma=use_goma,
+      use_remoteexec=use_remoteexec,
       incremental_build=False,
       setup_board=False,
       dryrun=dryrun)
@@ -251,38 +269,35 @@
       # No packages to report, so just exit with an error code.
       return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
 
-    # We need to report the failed packages.
-    for pkg_info in e.failed_packages:
-      package_info_msg = output_proto.failed_packages.add()
-      controller_util.serialize_package_info(pkg_info, package_info_msg)
+    controller_util.retrieve_package_log_paths(e, output_proto, target_sysroot)
 
     return controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE
+  finally:
+    # Copy goma logs to specified directory if there is a goma_config and
+    # it contains a log_dir to store artifacts.
+    if input_proto.goma_config.log_dir.dir:
+      # Get the goma log directory based on the GLOG_log_dir env variable.
+      # TODO(crbug.com/1045001): Replace environment variable with query to
+      # goma object after goma refactoring allows this.
+      log_source_dir = os.getenv('GLOG_log_dir')
+      if not log_source_dir:
+        cros_build_lib.Die('GLOG_log_dir must be defined.')
+      archiver = goma_lib.LogsArchiver(
+          log_source_dir,
+          dest_dir=input_proto.goma_config.log_dir.dir,
+          stats_file=input_proto.goma_config.stats_file,
+          counterz_file=input_proto.goma_config.counterz_file)
+      archiver_tuple = archiver.Archive()
+      if archiver_tuple.stats_file:
+        output_proto.goma_artifacts.stats_file = archiver_tuple.stats_file
+      if archiver_tuple.counterz_file:
+        output_proto.goma_artifacts.counterz_file = archiver_tuple.counterz_file
+      output_proto.goma_artifacts.log_files[:] = archiver_tuple.log_files
 
   # Return without populating the response if it is a dryrun.
   if dryrun:
     return controller.RETURN_CODE_SUCCESS
 
-  # Copy goma logs to specified directory if there is a goma_config and
-  # it contains a log_dir to store artifacts.
-  if input_proto.goma_config.log_dir.dir:
-    # Get the goma log directory based on the GLOG_log_dir env variable.
-    # TODO(crbug.com/1045001): Replace environment variable with query to
-    # goma object after goma refactoring allows this.
-    log_source_dir = os.getenv('GLOG_log_dir')
-    if not log_source_dir:
-      cros_build_lib.Die('GLOG_log_dir must be defined.')
-    archiver = goma_lib.LogsArchiver(
-        log_source_dir,
-        dest_dir=input_proto.goma_config.log_dir.dir,
-        stats_file=input_proto.goma_config.stats_file,
-        counterz_file=input_proto.goma_config.counterz_file)
-    archiver_tuple = archiver.Archive()
-    if archiver_tuple.stats_file:
-      output_proto.goma_artifacts.stats_file = archiver_tuple.stats_file
-    if archiver_tuple.counterz_file:
-      output_proto.goma_artifacts.counterz_file = archiver_tuple.counterz_file
-    output_proto.goma_artifacts.log_files[:] = archiver_tuple.log_files
-
   # Read metric events log and pipe them into output_proto.events.
   deserialize_metrics_log(output_proto.events, prefix=build_target.name)
 
diff --git a/api/controller/sysroot_unittest.py b/api/controller/sysroot_unittest.py
index 9115eb1..906bf24 100644
--- a/api/controller/sysroot_unittest.py
+++ b/api/controller/sysroot_unittest.py
@@ -247,6 +247,12 @@
     self.sysroot = os.path.join(self.tempdir, 'board')
     self.invalid_sysroot = os.path.join(self.tempdir, 'invalid', 'sysroot')
     osutils.SafeMakedirs(self.sysroot)
+    # Set up portage log directory.
+    self.target_sysroot = sysroot_lib.Sysroot(self.sysroot)
+    self.portage_dir = os.path.join(self.tempdir, 'portage_logdir')
+    self.PatchObject(
+        sysroot_lib.Sysroot, 'portage_logdir', new=self.portage_dir)
+    osutils.SafeMakedirs(self.portage_dir)
 
   def _InputProto(self, build_target=None, sysroot_path=None,
                   compile_source=False):
@@ -265,6 +271,22 @@
     """Helper to build output proto instance."""
     return sysroot_pb2.InstallToolchainResponse()
 
+  def _CreatePortageLogFile(self, log_path, pkg_info, timestamp):
+    """Creates a log file for testing for individual packages built by Portage.
+
+    Args:
+      log_path (pathlike): the PORTAGE_LOGDIR path
+      pkg_info (PackageInfo): name components for log file.
+      timestamp (datetime): timestamp used to name the file.
+    """
+    path = os.path.join(log_path,
+                        f'{pkg_info.category}:{pkg_info.pvr}:' \
+                        f'{timestamp.strftime("%Y%m%d-%H%M%S")}.log')
+    osutils.WriteFile(path,
+                      f'Test log file for package {pkg_info.category}/'
+                      f'{pkg_info.package} written to {path}')
+    return path
+
   def testValidateOnly(self):
     """Sanity check that a validate only call does not execute any logic."""
     patch = self.PatchObject(sysroot_service, 'InstallToolchain')
@@ -344,9 +366,19 @@
     in_proto = self._InputProto(build_target=self.board,
                                 sysroot_path=self.sysroot)
 
-    err_pkgs = ['cat/pkg', 'cat2/pkg2']
+    err_pkgs = ['cat/pkg-1.0-r1', 'cat2/pkg2-1.0-r1']
     err_cpvs = [package_info.parse(pkg) for pkg in err_pkgs]
     expected = [('cat', 'pkg'), ('cat2', 'pkg2')]
+
+    new_logs = {}
+    for i, pkg in enumerate(err_pkgs):
+      self._CreatePortageLogFile(self.portage_dir, err_cpvs[i],
+                                 datetime.datetime(2021, 6, 9, 13, 37, 0))
+      new_logs[pkg] = self._CreatePortageLogFile(self.portage_dir, err_cpvs[i],
+                                                 datetime.datetime(2021, 6, 9,
+                                                                   16, 20, 0)
+                                                 )
+
     err = sysroot_lib.ToolchainInstallError('Error',
                                             cros_build_lib.CommandResult(),
                                             tc_info=err_cpvs)
@@ -356,6 +388,16 @@
                                              self.api_config)
     self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
     self.assertTrue(out_proto.failed_packages)
+    self.assertTrue(out_proto.failed_package_data)
+    # This needs to return 2 to indicate the available error response.
+    self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
+    for data in out_proto.failed_package_data:
+      package = controller_util.deserialize_package_info(data.name)
+      cat_pkg = (data.name.category, data.name.package_name)
+      self.assertIn(cat_pkg, expected)
+      self.assertEqual(data.log_path.path, new_logs[package.cpvr])
+
+    # TODO(b/206514844): remove when field is deleted
     for package in out_proto.failed_packages:
       cat_pkg = (package.category, package.package_name)
       self.assertIn(cat_pkg, expected)
@@ -372,6 +414,12 @@
     self.build_target = 'board'
     self.sysroot = os.path.join(self.tempdir, 'build', 'board')
     osutils.SafeMakedirs(self.sysroot)
+    # Set up portage log directory.
+    self.target_sysroot = sysroot_lib.Sysroot(self.sysroot)
+    self.portage_dir = os.path.join(self.tempdir, 'portage_logdir')
+    self.PatchObject(
+        sysroot_lib.Sysroot, 'portage_logdir', new=self.portage_dir)
+    osutils.SafeMakedirs(self.portage_dir)
     # Set up goma directories.
     self.goma_dir = os.path.join(self.tempdir, 'goma_dir')
     osutils.SafeMakedirs(self.goma_dir)
@@ -428,6 +476,21 @@
         path,
         timestamp.strftime('Goma log file created at: %Y/%m/%d %H:%M:%S'))
 
+  def _CreatePortageLogFile(self, log_path, pkg_info, timestamp):
+    """Creates a log file for testing for individual packages built by Portage.
+
+    Args:
+      log_path (pathlike): the PORTAGE_LOGDIR path
+      pkg_info (PackageInfo): name components for log file.
+      timestamp (datetime): timestamp used to name the file.
+    """
+    path = os.path.join(log_path,
+                        f'{pkg_info.category}:{pkg_info.pvr}:' \
+                        f'{timestamp.strftime("%Y%m%d-%H%M%S")}.log')
+    osutils.WriteFile(path, f'Test log file for package {pkg_info.category}/'
+                      f'{pkg_info.package} written to {path}')
+    return path
+
   def testValidateOnly(self):
     """Sanity check that a validate only call does not execute any logic."""
     patch = self.PatchObject(sysroot_service, 'BuildPackages')
@@ -553,6 +616,7 @@
         ],
         use_flags=[],
         use_goma=False,
+        use_remoteexec=False,
         incremental_build=False,
         setup_board=False,
         dryrun=False)
@@ -684,10 +748,18 @@
     out_proto = self._OutputProto()
 
     # Failed package info and expected list for verification.
-    err_pkgs = ['cat/pkg', 'cat2/pkg2']
-    err_cpvs = [package_info.SplitCPV(cpv, strict=False) for cpv in err_pkgs]
+    err_pkgs = ['cat/pkg-1.0-r3', 'cat2/pkg2-1.0-r1']
+    err_cpvs = [package_info.parse(cpv) for cpv in err_pkgs]
     expected = [('cat', 'pkg'), ('cat2', 'pkg2')]
 
+    new_logs = {}
+    for i, pkg in enumerate(err_pkgs):
+      self._CreatePortageLogFile(self.portage_dir, err_cpvs[i],
+                                 datetime.datetime(2021, 6, 9, 13, 37, 0))
+      new_logs[pkg] = self._CreatePortageLogFile(self.portage_dir, err_cpvs[i],
+                                                 datetime.datetime(2021, 6, 9,
+                                                                   16, 20, 0)
+                                                 )
     # Force error to be raised with the packages.
     error = sysroot_lib.PackageInstallError('Error',
                                             cros_build_lib.CommandResult(),
@@ -698,6 +770,13 @@
                                             self.api_config)
     # This needs to return 2 to indicate the available error response.
     self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
+    for data in out_proto.failed_package_data:
+      package = controller_util.deserialize_package_info(data.name)
+      cat_pkg = (data.name.category, data.name.package_name)
+      self.assertIn(cat_pkg, expected)
+      self.assertEqual(data.log_path.path, new_logs[package.cpvr])
+
+    # TODO(b/206514844): remove when field is deleted
     for package in out_proto.failed_packages:
       cat_pkg = (package.category, package.package_name)
       self.assertIn(cat_pkg, expected)
diff --git a/api/controller/test.py b/api/controller/test.py
index 3b5cdf7..a444a8f 100644
--- a/api/controller/test.py
+++ b/api/controller/test.py
@@ -20,9 +20,6 @@
 from chromite.api.gen.chromite.api import test_pb2
 from chromite.api.gen.chromiumos import common_pb2
 from chromite.api.gen.chromiumos.build.api import container_metadata_pb2
-from chromite.api.gen.chromiumos.test.api import coverage_rule_pb2
-from chromite.api.gen.chromiumos.test.api import dut_attribute_pb2
-from chromite.api.gen.chromiumos.test.api import test_suite_pb2
 from chromite.cbuildbot import goma_util
 from chromite.lib import build_target_lib
 from chromite.lib import chroot_lib
@@ -36,7 +33,6 @@
 from chromite.service import packages as packages_service
 from chromite.service import test
 from chromite.third_party.google.protobuf import json_format
-from chromite.third_party.google.protobuf import text_format
 from chromite.utils import key_value_store
 from chromite.utils import metrics
 
@@ -82,20 +78,18 @@
     pkg_info = package_info.parse(pkg)
     pkg_info_msg = output_proto.failed_packages.add()
     controller_util.serialize_package_info(pkg_info, pkg_info_msg)
+    failed_pkg_data_msg = output_proto.failed_package_data.add()
+    controller_util.serialize_package_info(pkg_info, failed_pkg_data_msg.name)
+    failed_pkg_data_msg.log_path.path = '/path/to/%s/log' % pkg
 
 
 @faux.success(_BuildTargetUnitTestResponse)
 @faux.error(_BuildTargetUnitTestFailedResponse)
-@validate.require('build_target.name')
-@validate.exists('result_path')
 @validate.require_each('packages', ['category', 'package_name'])
 @validate.validation_complete
 @metrics.collect_metrics
 def BuildTargetUnitTest(input_proto, output_proto, _config):
   """Run a build target's ebuild unit tests."""
-  # Required args.
-  result_path = input_proto.result_path
-
   # Method flags.
   # An empty sysroot means build packages was not run. This is used for
   # certain boards that need to use prebuilts (e.g. grunt's unittest-only).
@@ -125,6 +119,8 @@
 
   code_coverage = input_proto.flags.code_coverage
 
+  sysroot = sysroot_lib.Sysroot(build_target.root)
+
   result = test.BuildTargetUnitTest(
       build_target,
       chroot,
@@ -136,20 +132,17 @@
       filter_only_cros_workon=filter_only_cros_workon)
 
   if not result.success:
-    # Failed to run tests or some tests failed.
-    # Record all failed packages.
-    for pkg_info in result.failed_pkgs:
-      package_info_msg = output_proto.failed_packages.add()
-      controller_util.serialize_package_info(pkg_info, package_info_msg)
+    # Record all failed packages and retrieve log locations.
+    controller_util.retrieve_package_log_paths(
+        sysroot_lib.PackageInstallError('error installing packages',
+                                        cros_build_lib.CommandResult(),
+                                        packages=result.failed_pkgs),
+        output_proto, sysroot)
     if result.failed_pkgs:
       return controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE
     else:
       return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
 
-  sysroot = sysroot_lib.Sysroot(build_target.root)
-  tarball = test.BuildTargetUnitTestTarball(chroot, sysroot, result_path)
-  if tarball:
-    output_proto.tarball_path = tarball
   deserialize_metrics_log(output_proto.events, prefix=build_target.name)
 
 
@@ -166,6 +159,16 @@
             PLATFORM_DEV_DIR,
             'test/container/utils/build-dockerimage.sh'
         ),
+    'cros-test-finder':
+        os.path.join(
+            TEST_SERVICE_DIR,
+            'test_finder/docker/build-dockerimage.sh',
+        ),
+    'cros-testplan':
+        os.path.join(
+            TEST_SERVICE_DIR,
+            'plan/docker/build-dockerimage.sh',
+        ),
 }
 
 
@@ -200,9 +203,7 @@
   allowed_chars = set(string.ascii_letters+string.digits+'-_.')
   invalid_chars = set(tag) - allowed_chars
   if invalid_chars:
-    return 'saw one or more invalid characters: [{}]'.format(
-        ''.join(invalid_chars),
-    )
+    return f'saw one or more invalid characters: [{"".join(invalid_chars)}]'
 
   # Finally, max tag length is 128 characters
   if len(tag) > 128:
@@ -222,14 +223,12 @@
   allowed_chars = set(string.ascii_lowercase+string.digits+'-.')
   invalid_chars = set(key) - allowed_chars
   if invalid_chars:
-    return 'saw one or more invalid characters: [{}]'.format(
-        ''.join(invalid_chars),
-    )
+    return f'saw one or more invalid characters: [{"".join(invalid_chars)}]'
 
   # Repeated . and - aren't allowed
   for char in '.-':
-    if char*2 in key:
-      return "'{}' can\'t be repeated in label key".format(char)
+    if char * 2 in key:
+      return f"'{char}' can\'t be repeated in label key"
 
 
 @faux.success(_BuildTestServiceContainersResponse)
@@ -249,7 +248,7 @@
 
   tags = ','.join(input_proto.tags)
   labels = (
-      '{}={}'.format(key, value) for key, value in input_proto.labels.items()
+      f'{key}={value}' for key, value in input_proto.labels.items()
   )
 
   for human_name, build_script in TEST_CONTAINER_BUILD_SCRIPTS.items():
@@ -260,6 +259,11 @@
       # with maintaining stdout hygiene.  Stdout and stderr are combined to
       # form the error log in response to any errors.
       cmd = [build_script, chroot.path, sysroot.path]
+
+      if input_proto.HasField('repository'):
+        cmd += ['--host', input_proto.repository.hostname]
+        cmd += ['--project', input_proto.repository.project]
+
       cmd += ['--tags', tags]
       cmd += ['--output', output_path]
       cmd += labels
@@ -457,68 +461,3 @@
           })
 
   return generated
-
-
-def _GetCoverageRulesResponseSuccess(
-    _input_proto, output_proto: test_pb2.GetCoverageRulesResponse, _config):
-  output_proto.coverage_rules.append(
-      coverage_rule_pb2.CoverageRule(
-          name='kernel:4.4',
-          test_suites=[
-              test_suite_pb2.TestSuite(
-                  test_case_tag_criteria=test_suite_pb2.TestSuite
-                  .TestCaseTagCriteria(tags=['kernel']))
-          ],
-          dut_criteria=[
-              dut_attribute_pb2.DutCriterion(
-                  attribute_id=dut_attribute_pb2.DutAttribute.Id(
-                      value='system_build_target'),
-                  values=['overlayA'],
-              )
-          ],
-      ),)
-
-
-@faux.success(_GetCoverageRulesResponseSuccess)
-@faux.empty_error
-@validate.require('source_test_plans')
-@validate.exists('dut_attribute_list.path', 'build_metadata_list.path',
-                 'flat_config_list.path')
-@validate.validation_complete
-def GetCoverageRules(input_proto: test_pb2.GetCoverageRulesRequest,
-                     output_proto: test_pb2.GetCoverageRulesResponse, _config):
-  """Call the testplan tool to generate CoverageRules."""
-  source_test_plans = input_proto.source_test_plans
-  dut_attribute_list = input_proto.dut_attribute_list
-  build_metadata_list = input_proto.build_metadata_list
-  flat_config_list = input_proto.flat_config_list
-
-  cmd = [
-      'testplan', 'generate', '-dutattributes', dut_attribute_list.path,
-      '-buildmetadata', build_metadata_list.path, '-flatconfiglist',
-      flat_config_list.path, '-logtostderr', '-v', '2'
-  ]
-
-  with osutils.TempDir(prefix='get_coverage_rules_input') as tempdir:
-    # Write all input files required by testplan, and read the output file
-    # containing CoverageRules.
-    for i, plan in enumerate(source_test_plans):
-      plan_path = os.path.join(tempdir, 'source_test_plan_%d.textpb' % i)
-      osutils.WriteFile(plan_path, text_format.MessageToString(plan))
-      cmd.extend(['-plan', plan_path])
-
-    out_path = os.path.join(tempdir, 'out.jsonpb')
-    cmd.extend(['-out', out_path])
-
-    cros_build_lib.run(cmd)
-
-    out_text = osutils.ReadFile(out_path)
-
-  # The output file contains CoverageRules as jsonpb, separated by newlines.
-  coverage_rules = []
-  for out_line in out_text.splitlines():
-    coverage_rule = coverage_rule_pb2.CoverageRule()
-    json_format.Parse(out_line, coverage_rule)
-    coverage_rules.append(coverage_rule)
-
-  output_proto.coverage_rules.extend(coverage_rules)
diff --git a/api/controller/test_unittest.py b/api/controller/test_unittest.py
index d6487ca..310ffab 100644
--- a/api/controller/test_unittest.py
+++ b/api/controller/test_unittest.py
@@ -5,24 +5,17 @@
 """The test controller tests."""
 
 import contextlib
+import datetime
 import os
 from unittest import mock
 
 from chromite.api import api_config
 from chromite.api import controller
+from chromite.api.controller import controller_util
 from chromite.api.controller import test as test_controller
 from chromite.api.gen.chromiumos import common_pb2
 from chromite.api.gen.chromite.api import test_pb2
 from chromite.api.gen.chromiumos.build.api import container_metadata_pb2
-from chromite.api.gen.chromiumos.build.api import system_image_pb2
-from chromite.api.gen.chromiumos.build.api import portage_pb2
-from chromite.api.gen.chromiumos.config.payload import flat_config_pb2
-from chromite.api.gen.chromiumos.config.api import design_pb2
-from chromite.api.gen.chromiumos.config.api import design_id_pb2
-from chromite.api.gen.chromiumos.test.api import coverage_rule_pb2
-from chromite.api.gen.chromiumos.test.api import dut_attribute_pb2
-from chromite.api.gen.chromiumos.test.api import test_suite_pb2
-from chromite.api.gen.chromiumos.test.plan import source_test_plan_pb2
 from chromite.lib import build_target_lib
 from chromite.lib import chroot_lib
 from chromite.lib import cros_build_lib
@@ -108,6 +101,16 @@
                               api_config.ApiConfigMixin):
   """Tests for the UnitTest function."""
 
+  def setUp(self):
+    # Set up portage log directory.
+    self.sysroot = os.path.join(self.tempdir, 'build', 'board')
+    osutils.SafeMakedirs(self.sysroot)
+    self.target_sysroot = sysroot_lib.Sysroot(self.sysroot)
+    self.portage_dir = os.path.join(self.tempdir, 'portage_logdir')
+    self.PatchObject(
+        sysroot_lib.Sysroot, 'portage_logdir', new=self.portage_dir)
+    osutils.SafeMakedirs(self.portage_dir)
+
   def _GetInput(self,
                 board=None,
                 result_path=None,
@@ -140,6 +143,22 @@
     """Helper to get an empty output message instance."""
     return test_pb2.BuildTargetUnitTestResponse()
 
+  def _CreatePortageLogFile(self, log_path, pkg_info, timestamp):
+    """Creates a log file for testing for individual packages built by Portage.
+
+    Args:
+      log_path (pathlike): the PORTAGE_LOGDIR path
+      pkg_info (PackageInfo): name components for log file.
+      timestamp (datetime): timestamp used to name the file.
+    """
+    path = os.path.join(log_path,
+                        f'{pkg_info.category}:{pkg_info.pvr}:' \
+                        f'{timestamp.strftime("%Y%m%d-%H%M%S")}.log')
+    osutils.WriteFile(path,
+                      f'Test log file for package {pkg_info.category}/'
+                      f'{pkg_info.package} written to {path}')
+    return path
+
   def testValidateOnly(self):
     """Sanity check that a validate only call does not execute any logic."""
     patch = self.PatchObject(test_service, 'BuildTargetUnitTest')
@@ -177,31 +196,6 @@
     self.assertEqual(response.failed_packages[1].category, 'cat')
     self.assertEqual(response.failed_packages[1].package_name, 'pkg')
 
-  def testNoArgumentFails(self):
-    """Test no arguments fails."""
-    input_msg = self._GetInput()
-    output_msg = self._GetOutput()
-    with self.assertRaises(cros_build_lib.DieSystemExit):
-      test_controller.BuildTargetUnitTest(input_msg, output_msg,
-                                          self.api_config)
-
-  def testNoBuildTargetFails(self):
-    """Test missing build target name fails."""
-    input_msg = self._GetInput(result_path=self.tempdir)
-    output_msg = self._GetOutput()
-    with self.assertRaises(cros_build_lib.DieSystemExit):
-      test_controller.BuildTargetUnitTest(input_msg, output_msg,
-                                          self.api_config)
-
-  def testNoResultPathFails(self):
-    """Test missing result path fails."""
-    # Missing result_path.
-    input_msg = self._GetInput(board='board')
-    output_msg = self._GetOutput()
-    with self.assertRaises(cros_build_lib.DieSystemExit):
-      test_controller.BuildTargetUnitTest(input_msg, output_msg,
-                                          self.api_config)
-
   def testInvalidPackageFails(self):
     """Test missing result path fails."""
     # Missing result_path.
@@ -218,8 +212,16 @@
     tempdir = osutils.TempDir(base_dir=self.tempdir)
     self.PatchObject(osutils, 'TempDir', return_value=tempdir)
 
-    pkgs = ['cat/pkg', 'foo/bar']
+    pkgs = ['cat/pkg-1.0-r1', 'foo/bar-2.0-r1']
+    cpvrs = [package_info.parse(pkg) for pkg in pkgs]
     expected = [('cat', 'pkg'), ('foo', 'bar')]
+    new_logs = {}
+    for i, pkg in enumerate(pkgs):
+      self._CreatePortageLogFile(self.portage_dir, cpvrs[i],
+                                 datetime.datetime(2021, 6, 9, 13, 37, 0))
+      new_logs[pkg] = self._CreatePortageLogFile(self.portage_dir, cpvrs[i],
+                                                 datetime.datetime(2021, 6, 9,
+                                                                   16, 20, 0))
 
     result = test_service.BuildTargetUnitTestResult(1, None)
     result.failed_pkgs = [package_info.parse(p) for p in pkgs]
@@ -233,11 +235,21 @@
 
     self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
     self.assertTrue(output_msg.failed_packages)
+    self.assertTrue(output_msg.failed_package_data)
+    # TODO(b/206514844): remove when field is deleted
     failed = []
     for pi in output_msg.failed_packages:
       failed.append((pi.category, pi.package_name))
     self.assertCountEqual(expected, failed)
 
+    failed_with_logs = []
+    for data in output_msg.failed_package_data:
+      failed_with_logs.append((data.name.category, data.name.package_name))
+      package = controller_util.deserialize_package_info(data.name)
+      self.assertEqual(data.log_path.path, new_logs[package.cpvr])
+    self.assertCountEqual(expected, failed_with_logs)
+
+
   def testOtherBuildScriptFailure(self):
     """Test build script failure due to non-package emerge error."""
     tempdir = osutils.TempDir(base_dir=self.tempdir)
@@ -248,8 +260,8 @@
 
     pkgs = ['foo/bar', 'cat/pkg']
     blocklist = [package_info.SplitCPV(p, strict=False) for p in pkgs]
-    input_msg = self._GetInput(board='board', result_path=self.tempdir,
-                               empty_sysroot=True, blocklist=blocklist)
+    input_msg = self._GetInput(board='board', empty_sysroot=True,
+                               blocklist=blocklist)
     output_msg = self._GetOutput()
 
     rc = test_controller.BuildTargetUnitTest(input_msg, output_msg,
@@ -262,21 +274,15 @@
     """Test BuildTargetUnitTest successful call."""
     pkgs = ['foo/bar', 'cat/pkg']
     packages = [package_info.SplitCPV(p, strict=False) for p in pkgs]
-    input_msg = self._GetInput(
-        board='board', result_path=self.tempdir, packages=packages)
+    input_msg = self._GetInput(board='board', packages=packages)
 
     result = test_service.BuildTargetUnitTestResult(0, None)
     self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
 
-    tarball_result = os.path.join(input_msg.result_path, 'unit_tests.tar')
-    self.PatchObject(test_service, 'BuildTargetUnitTestTarball',
-                     return_value=tarball_result)
-
     response = self._GetOutput()
     test_controller.BuildTargetUnitTest(input_msg, response,
                                         self.api_config)
-    self.assertEqual(response.tarball_path,
-                     os.path.join(input_msg.result_path, 'unit_tests.tar'))
+    self.assertFalse(response.failed_packages)
 
 
 class DockerConstraintsTest(cros_test_lib.MockTestCase):
@@ -877,106 +883,3 @@
     self.assertEqual(result[0]['type'], self.UNIT_TEST_ARTIFACT_TYPE)
     self.assertEqual(result[1]['paths'], ['test'])
     self.assertEqual(result[1]['type'], self.CODE_COVERAGE_LLVM_ARTIFACT_TYPE)
-
-
-class GetCoverageRulesTest(cros_test_lib.RunCommandTempDirTestCase,
-                           api_config.ApiConfigMixin):
-  """Tests for GetCoverageRules."""
-
-  def _Input(self):
-    """Returns a sample GetCoverageRulesRequest for testing."""
-    build_metadata_list_path = os.path.join(self.tempdir,
-                                            'build_metadata_list.jsonproto')
-    build_metadata_list = system_image_pb2.SystemImage.BuildMetadataList(
-        values=[
-            system_image_pb2.SystemImage.BuildMetadata(
-                build_target=system_image_pb2.SystemImage.BuildTarget(
-                    portage_build_target=portage_pb2.Portage.BuildTarget(
-                        overlay_name='overlayA')),
-                package_summary=system_image_pb2.SystemImage.BuildMetadata
-                .PackageSummary(
-                    kernel=system_image_pb2.SystemImage.BuildMetadata.Kernel(
-                        version='4.4')))
-        ])
-    osutils.WriteFile(build_metadata_list_path,
-                      json_format.MessageToJson(build_metadata_list))
-
-    dut_attribute_list_path = os.path.join(self.tempdir,
-                                           'dut_attribute_list.jsonproto')
-    dut_attribute_list = dut_attribute_pb2.DutAttributeList(dut_attributes=[
-        dut_attribute_pb2.DutAttribute(
-            id=dut_attribute_pb2.DutAttribute.Id(value='system_build_target'))
-    ])
-    osutils.WriteFile(dut_attribute_list_path,
-                      json_format.MessageToJson(dut_attribute_list))
-
-    flat_config_list_path = os.path.join(self.tempdir,
-                                         'flat_config_list.jsonproto')
-    flat_config_list = flat_config_pb2.FlatConfigList(values=[
-        flat_config_pb2.FlatConfig(
-            hw_design=design_pb2.Design(
-                id=design_id_pb2.DesignId(value='design1')
-            )
-        )
-    ])
-    osutils.WriteFile(flat_config_list_path,
-                      json_format.MessageToJson(flat_config_list))
-
-    return test_pb2.GetCoverageRulesRequest(
-        source_test_plans=[
-            source_test_plan_pb2.SourceTestPlan(
-                requirements=source_test_plan_pb2.SourceTestPlan.Requirements(
-                    kernel_versions=source_test_plan_pb2.SourceTestPlan
-                    .Requirements.KernelVersions()),
-                test_tags=['kernel']),
-        ],
-        build_metadata_list=common_pb2.Path(
-            path=build_metadata_list_path, location=common_pb2.Path.OUTSIDE),
-        dut_attribute_list=common_pb2.Path(
-            path=dut_attribute_list_path, location=common_pb2.Path.OUTSIDE),
-        flat_config_list=common_pb2.Path(
-            path=flat_config_list_path, location=common_pb2.Path.OUTSIDE),
-    )
-
-  @staticmethod
-  def _Output():
-    """Returns a sample GetCoverageRulesResponse for testing."""
-    return test_pb2.GetCoverageRulesResponse(coverage_rules=[
-        coverage_rule_pb2.CoverageRule(
-            name='kernel:4.4',
-            test_suites=[
-                test_suite_pb2.TestSuite(
-                    test_case_tag_criteria=test_suite_pb2.TestSuite
-                    .TestCaseTagCriteria(tags=['kernel']))
-            ],
-            dut_criteria=[
-                dut_attribute_pb2.DutCriterion(
-                    attribute_id=dut_attribute_pb2.DutAttribute.Id(
-                        value='system_build_target'),
-                    values=['overlayA'],
-                )
-            ])
-    ])
-
-  @staticmethod
-  def _write_coverage_rules(path, coverage_rules):
-    """Write a list of CoverageRules in the same format as testplan."""
-    osutils.WriteFile(
-        path, '\n'.join(
-            json_format.MessageToJson(rule).replace('\n', '')
-            for rule in coverage_rules))
-
-  def testWritesInputsAndReturnsCoverageRules(self):
-    """Test inputs are written, and output of testplan is parsed."""
-    output_proto = test_pb2.GetCoverageRulesResponse()
-
-    self.rc.SetDefaultCmdResult(
-        side_effect=lambda _: self._write_coverage_rules(
-            os.path.join(self.tempdir, 'out.jsonpb'),
-            self._Output().coverage_rules))
-    self.PatchObject(osutils.TempDir, '__enter__', return_value=self.tempdir)
-
-    test_controller.GetCoverageRules(self._Input(), output_proto,
-                                     self.api_config)
-
-    self.assertEqual(output_proto, self._Output())
diff --git a/api/controller/toolchain.py b/api/controller/toolchain.py
index 1c6c4d1..96acd78 100644
--- a/api/controller/toolchain.py
+++ b/api/controller/toolchain.py
@@ -6,6 +6,9 @@
 
 import collections
 import logging
+import os
+from pathlib import Path
+import re
 
 from chromite.api import controller
 from chromite.api import faux
@@ -16,8 +19,12 @@
 from chromite.api.gen.chromiumos.builder_config_pb2 import BuilderConfig
 from chromite.lib import chroot_util
 from chromite.lib import cros_build_lib
+from chromite.lib import osutils
 from chromite.lib import toolchain_util
-from chromite.scripts import tricium_cargo_clippy
+
+if cros_build_lib.IsInsideChroot():
+  # Only used for linting in chroot and requires yaml which is only in chroot
+  from chromite.scripts import tricium_cargo_clippy, tricium_clang_tidy
 
 
 _Handlers = collections.namedtuple('_Handlers', ['name', 'prepare', 'bundle'])
@@ -85,6 +92,8 @@
         'VerifiedKernelCwpAfdoFile'
 }
 
+TIDY_BASE_DIR = Path('/tmp/linting_output/clang-tidy')
+
 
 def _GetProfileInfoDict(profile_info):
   """Convert profile_info to a dict.
@@ -192,7 +201,7 @@
 @validate.exists('output_dir')
 @validate.validation_complete
 def BundleArtifacts(input_proto, output_proto, _config):
-  """Bundle toolchain artifacts.
+  """Bundle valid toolchain artifacts.
 
   The handlers (from _TOOLCHAIN_ARTIFACT_HANDLERS above) are called with:
       artifact_name (str): name of the artifact type
@@ -217,20 +226,45 @@
 
   profile_info = _GetProfileInfoDict(input_proto.profile_info)
 
+  output_path = Path(input_proto.output_dir)
+
   for artifact_type in input_proto.artifact_types:
     if artifact_type not in _TOOLCHAIN_ARTIFACT_HANDLERS:
       logging.error('%s not understood', artifact_type)
       return controller.RETURN_CODE_UNRECOVERABLE
+
     handler = _TOOLCHAIN_ARTIFACT_HANDLERS[artifact_type]
-    if handler and handler.bundle:
-      artifacts = handler.bundle(handler.name, chroot, input_proto.sysroot.path,
-                                 input_proto.sysroot.build_target.name,
-                                 input_proto.output_dir, profile_info)
-      if artifacts:
-        art_info = output_proto.artifacts_info.add()
-        art_info.artifact_type = artifact_type
-        for artifact in artifacts:
-          art_info.artifacts.add().path = artifact
+    if not handler or not handler.bundle:
+      logging.warning('%s does not have a handler with a bundle function.',
+                      artifact_type)
+      continue
+
+    artifacts = handler.bundle(handler.name, chroot, input_proto.sysroot.path,
+                               input_proto.sysroot.build_target.name,
+                               input_proto.output_dir, profile_info)
+    if not artifacts:
+      continue
+
+    # Filter out artifacts that do not exist or are empty.
+    usable_artifacts = []
+    for artifact in artifacts:
+      artifact_path = output_path / artifact
+      if not artifact_path.exists():
+        logging.warning('%s is not in the output directory.', artifact)
+      elif not artifact_path.stat().st_size:
+        logging.warning('%s is empty.', artifact)
+      else:
+        usable_artifacts.append(artifact)
+
+    if not usable_artifacts:
+      logging.warning('No usable artifacts for artifact type %s', artifact_type)
+      continue
+
+    # Add all usable artifacts.
+    art_info = output_proto.artifacts_info.add()
+    art_info.artifact_type = artifact_type
+    for artifact in usable_artifacts:
+      art_info.artifacts.add().path = artifact
 
 
 def _GetUpdatedFilesResponse(_input_proto, output_proto, _config):
@@ -281,83 +315,105 @@
     # No commit footer is added for now. Can add more here if needed
 
 
-# TODO(crbug/1019868): Remove legacy code when cbuildbot builders are gone.
-_NAMES_FOR_AFDO_ARTIFACTS = {
-    toolchain_pb2.ORDERFILE: 'orderfile',
-    toolchain_pb2.KERNEL_AFDO: 'kernel_afdo',
-    toolchain_pb2.CHROME_AFDO: 'chrome_afdo'
+@faux.all_empty
+@validate.exists('sysroot.path')
+@validate.require('packages')
+@validate.validation_complete
+def EmergeWithLinting(input_proto, output_proto, _config):
+  """Emerge packages with linter features enabled and retrieves all findings.
+
+  Args:
+    input_proto (LinterRequest): The nput proto with package and sysroot info.
+    output_proto (LinterResponse): The output proto where findings are stored.
+    _config (api_config.ApiConfig): The API call config (unused).
+  """
+  packages = [
+      f'{package.category}/{package.package_name}'
+      for package in input_proto.packages]
+
+  # rm any existing lints from clang tidy
+  osutils.RmDir(TIDY_BASE_DIR, ignore_missing=True, sudo=True)
+  osutils.SafeMakedirs(TIDY_BASE_DIR, 0o777, sudo=True)
+
+  emerge_cmd = chroot_util.GetEmergeCommand(input_proto.sysroot.path)
+  cros_build_lib.sudo_run(
+      emerge_cmd + packages,
+      preserve_env=True,
+      extra_env={
+          'ENABLE_RUST_CLIPPY': 1,
+          'WITH_TIDY': 'tricium',
+          'FEATURES': 'noclean'
+      }
+  )
+
+  # FIXME(b/195056381): default git-repo should be replaced with logic in
+  # build_linters recipe to detect the repo path for applied patches.
+  # As of 01-05-21 only platform2 is supported so this value works temporarily.
+  git_repo_path = '/mnt/host/source/src/platform2/'
+
+  linter_findings = _fetch_clippy_lints(git_repo_path)
+  linter_findings.extend(_fetch_tidy_lints(git_repo_path))
+  linter_findings = _filter_linter_findings(linter_findings, git_repo_path)
+  output_proto.findings.extend(linter_findings)
+
+
+LINTER_CODES = {
+    'clang_tidy': toolchain_pb2.LinterFinding.CLANG_TIDY,
+    'cargo_clippy': toolchain_pb2.LinterFinding.CARGO_CLIPPY
 }
 
 
-# TODO(crbug/1019868): Remove legacy code when cbuildbot builders are gone.
-# Using a function instead of a dict because we need to mock these
-# functions in unittest, and mock doesn't play well with a dict definition.
-def _GetMethodForUpdatingAFDOArtifacts(artifact_type):
-  return {
-      toolchain_pb2.ORDERFILE: toolchain_util.OrderfileUpdateChromeEbuild,
-      toolchain_pb2.KERNEL_AFDO: toolchain_util.AFDOUpdateKernelEbuild,
-      toolchain_pb2.CHROME_AFDO: toolchain_util.AFDOUpdateChromeEbuild
-  }[artifact_type]
+def _filter_linter_findings(findings, git_repo_path):
+  """Filters a findings to keep only those concerning modified lines."""
+  new_findings = []
+  new_lines = _get_added_lines({git_repo_path: 'HEAD'})
+  for finding in findings:
+    for loc in finding.locations:
+      for (addition_start, addition_end) in new_lines.get(loc.filepath, set()):
+        if addition_start <= loc.line_start < addition_end:
+          new_findings.append(finding)
+  return new_findings
 
 
-# TODO(crbug/1019868): Remove legacy code when cbuildbot builders are gone.
-def _UpdateEbuildWithAFDOArtifactsResponse(_input_proto, output_proto, _config):
-  """Add successful status to the faux response."""
-  output_proto.status = True
-
-
-# TODO(crbug/1019868): Remove legacy code when cbuildbot builders are gone.
-@faux.success(_UpdateEbuildWithAFDOArtifactsResponse)
-@faux.empty_error
-@validate.require('build_target.name')
-@validate.is_in('artifact_type', _NAMES_FOR_AFDO_ARTIFACTS)
-@validate.validation_complete
-def UpdateEbuildWithAFDOArtifacts(input_proto, output_proto, _config):
-  """Update Chrome or kernel ebuild with most recent unvetted artifacts.
+def _get_added_lines(git_repos):
+  """Parses the lines with additions from fit diff for the provided repos.
 
   Args:
-    input_proto (VerifyAFDOArtifactsRequest): The input proto
-    output_proto (VerifyAFDOArtifactsResponse): The output proto
-    _config (api_config.ApiConfig): The API call config.
+    git_repos: a dictionary mapping repo paths to hashes for `git diff`
+
+  Returns:
+    A dictionary mapping modified filepaths to sets of tuples where each
+    tuple is a (start_line, end_line) pair noting which lines were modified.
+    Note that start_line is inclusive, and end_line is exclusive.
   """
-  board = input_proto.build_target.name
-  update_method = _GetMethodForUpdatingAFDOArtifacts(input_proto.artifact_type)
-  output_proto.status = update_method(board)
+  new_lines = {}
+  file_path_pattern = re.compile(r'^\+\+\+ b/(?P<file_path>.*)$')
+  position_pattern = re.compile(
+      r'^@@ -\d+(?:,\d+)? \+(?P<line_num>\d+)(?:,(?P<lines_added>\d+))? @@')
+  for git_repo, git_hash in git_repos.items():
+    cmd = f'git -C {git_repo} diff -U0 {git_hash}^...{git_hash}'
+    diff = cros_build_lib.run(cmd, capture_output=True, shell=True,
+                              encoding='utf-8').output
+    current_file = ''
+    for line in diff.splitlines():
+      file_path_match = re.match(file_path_pattern, str(line))
+      if file_path_match:
+        current_file = file_path_match.group('file_path')
+        continue
+      position_match = re.match(position_pattern, str(line))
+      if position_match:
+        if current_file not in new_lines:
+          new_lines[current_file] = set()
+        line_num = int(position_match.group('line_num'))
+        line_count = position_match.group('lines_added')
+        line_count = int(line_count) if line_count is not None else 1
+        new_lines[current_file].add((line_num, line_num + line_count))
+  return new_lines
 
 
-# TODO(crbug/1019868): Remove legacy code when cbuildbot builders are gone.
-def _UploadVettedAFDOArtifactsResponse(_input_proto, output_proto, _config):
-  """Add successful status to the faux response."""
-  output_proto.status = True
-
-
-# TODO(crbug/1019868): Remove legacy code when cbuildbot builders are gone.
-@faux.success(_UploadVettedAFDOArtifactsResponse)
-@faux.empty_error
-@validate.require('build_target.name')
-@validate.is_in('artifact_type', _NAMES_FOR_AFDO_ARTIFACTS)
-@validate.validation_complete
-def UploadVettedAFDOArtifacts(input_proto, output_proto, _config):
-  """Upload a vetted orderfile to GS bucket.
-
-  Args:
-    input_proto (VerifyAFDOArtifactsRequest): The input proto
-    output_proto (VerifyAFDOArtifactsResponse): The output proto
-    _config (api_config.ApiConfig): The API call config.
-  """
-  board = input_proto.build_target.name
-  artifact_type = _NAMES_FOR_AFDO_ARTIFACTS[input_proto.artifact_type]
-  output_proto.status = toolchain_util.UploadAndPublishVettedAFDOArtifacts(
-      artifact_type, board)
-
-
-def _fetch_clippy_lints():
+def _fetch_clippy_lints(git_repo_path):
   """Get lints created by Cargo Clippy during emerge."""
   lints_dir = '/tmp/cargo_clippy'
-  # FIXME(b/195056381): default git-repo should be replaced with logic in
-  # build_linters recipe to detect the repo path for applied patches.
-  # As of 07-29-21 only platform2 is supported so this value works temporarily.
-  git_repo_path = '/mnt/host/source/src/platform2'
   findings = tricium_cargo_clippy.parse_files(lints_dir, git_repo_path)
   findings = tricium_cargo_clippy.filter_diagnostics(findings)
   findings_protos = []
@@ -374,24 +430,46 @@
     findings_protos.append(
         toolchain_pb2.LinterFinding(
             message=finding.message,
-            locations=location_protos
+            locations=location_protos,
+            linter=LINTER_CODES['cargo_clippy']
         )
     )
   return findings_protos
 
 
-@validate.exists('sysroot.path')
-@validate.require('packages')
-@validate.validation_complete
-def GetClippyLints(input_proto, output_proto, _config):
-  """Emerges the given packages and retrieves any findings from Cargo Clippy."""
-  emerge_cmd = chroot_util.GetEmergeCommand(input_proto.sysroot.path)
-  packages = [
-      f'{package.category}/{package.package_name}'
-      for package in input_proto.packages]
-  cros_build_lib.sudo_run(
-      emerge_cmd + packages,
-      preserve_env=True,
-      extra_env={'ENABLE_RUST_CLIPPY': 1}
-  )
-  output_proto.findings.extend(_fetch_clippy_lints())
+def _fetch_tidy_lints(git_repo_path):
+  """Get lints created by Clang Tidy during emerge."""
+
+  def resolve_file_path(file_path):
+    # Remove git repo from prefix
+    file_path = re.sub('^' + git_repo_path, '/', str(file_path))
+    # Remove ebuild work directories from prefix
+    # Such as: "**/<package>-9999/work/<package>-9999/"
+    #      or: "**/<package>-0.24.52-r9/work/<package>-0.24.52/"
+    return re.sub(r'(.*/)?([^/]+)-[^/]+/work/[^/]+/+', '', file_path)
+
+  lints = set()
+  for filename in os.listdir(TIDY_BASE_DIR):
+    if filename.endswith('.json'):
+      invocation_result = tricium_clang_tidy.parse_tidy_invocation(
+          TIDY_BASE_DIR / filename)
+      meta, complaints = invocation_result
+      assert not meta.exit_code, (
+          f'Invoking clang-tidy on {meta.lint_target} with flags '
+          f'{meta.invocation} exited with code {meta.exit_code}; '
+          f'output:\n{meta.stdstreams}')
+      lints.update(complaints)
+  return [
+      toolchain_pb2.LinterFinding(
+          message=lint.message,
+          locations=[
+              toolchain_pb2.LinterFindingLocation(
+                  filepath=resolve_file_path(lint.file_path),
+                  line_start=lint.line_number,
+                  line_end=lint.line_number
+              )
+          ],
+          linter=LINTER_CODES['clang_tidy']
+      )
+      for lint in tricium_clang_tidy.filter_tidy_lints(None, None, lints)
+  ]
diff --git a/api/controller/toolchain_unittest.py b/api/controller/toolchain_unittest.py
index 8f1a4ea..4029ad9 100644
--- a/api/controller/toolchain_unittest.py
+++ b/api/controller/toolchain_unittest.py
@@ -4,6 +4,8 @@
 
 """Unittests for Toolchain-related operations."""
 
+import os
+
 from chromite.api import api_config
 from chromite.api import controller
 from chromite.api.controller import toolchain
@@ -15,6 +17,7 @@
 
 from chromite.lib import cros_build_lib
 from chromite.lib import cros_test_lib
+from chromite.lib import osutils
 from chromite.lib import toolchain_util
 
 # pylint: disable=protected-access
@@ -32,12 +35,6 @@
     self.board = 'board'
     self.response = toolchain_pb2.VerifyAFDOArtifactsResponse()
     self.invalid_artifact_type = toolchain_pb2.BENCHMARK_AFDO
-    self.orderfile_command = self.PatchObject(
-        toolchain_util, 'OrderfileUpdateChromeEbuild', return_value=True)
-    self.kernel_command = self.PatchObject(
-        toolchain_util, 'AFDOUpdateKernelEbuild', return_value=True)
-    self.chrome_command = self.PatchObject(
-        toolchain_util, 'AFDOUpdateChromeEbuild', return_value=True)
     self.PatchObject(cros_build_lib, 'Die', new=self.mock_die)
 
   def _GetRequest(self, build_target=None, artifact_type=None):
@@ -46,131 +43,6 @@
         artifact_type=artifact_type,
     )
 
-  def testValidateOnly(self):
-    """Sanity check that a validate only call does not execute any logic."""
-    patch = self.PatchObject(toolchain_util, 'OrderfileUpdateChromeEbuild')
-    request = self._GetRequest(
-        build_target=self.board, artifact_type=toolchain_pb2.ORDERFILE)
-    toolchain.UpdateEbuildWithAFDOArtifacts(request, self.response,
-                                            self.validate_only_config)
-    patch.assert_not_called()
-
-  def testMockCall(self):
-    """Test that a mock call does not execute logic, returns mock value."""
-    patch = self.PatchObject(toolchain_util, 'OrderfileUpdateChromeEbuild')
-    request = self._GetRequest(
-        build_target=self.board, artifact_type=toolchain_pb2.ORDERFILE)
-    toolchain.UpdateEbuildWithAFDOArtifacts(request, self.response,
-                                            self.mock_call_config)
-    patch.assert_not_called()
-    self.assertEqual(self.response.status, True)
-
-  def testWrongArtifactType(self):
-    """Test passing wrong artifact type."""
-    request = self._GetRequest(
-        build_target=self.board, artifact_type=self.invalid_artifact_type)
-    with self.assertRaises(cros_build_lib.DieSystemExit) as context:
-      toolchain.UpdateEbuildWithAFDOArtifacts(request, self.response,
-                                              self.api_config)
-    self.assertIn('artifact_type (%d) must be in' % self.invalid_artifact_type,
-                  str(context.exception))
-
-  def testOrderfileSuccess(self):
-    """Test the command is called correctly with orderfile."""
-    request = self._GetRequest(
-        build_target=self.board, artifact_type=toolchain_pb2.ORDERFILE)
-    toolchain.UpdateEbuildWithAFDOArtifacts(request, self.response,
-                                            self.api_config)
-    self.orderfile_command.assert_called_once_with(self.board)
-    self.kernel_command.assert_not_called()
-    self.chrome_command.assert_not_called()
-
-  def testKernelAFDOSuccess(self):
-    """Test the command is called correctly with kernel afdo."""
-    request = self._GetRequest(
-        build_target=self.board, artifact_type=toolchain_pb2.KERNEL_AFDO)
-    toolchain.UpdateEbuildWithAFDOArtifacts(request, self.response,
-                                            self.api_config)
-    self.kernel_command.assert_called_once_with(self.board)
-    self.orderfile_command.assert_not_called()
-    self.chrome_command.assert_not_called()
-
-  def testChromeAFDOSuccess(self):
-    """Test the command is called correctly with Chrome afdo."""
-    request = self._GetRequest(
-        build_target=self.board, artifact_type=toolchain_pb2.CHROME_AFDO)
-    toolchain.UpdateEbuildWithAFDOArtifacts(request, self.response,
-                                            self.api_config)
-    self.chrome_command.assert_called_once_with(self.board)
-    self.orderfile_command.assert_not_called()
-    self.kernel_command.assert_not_called()
-
-
-class UploadVettedFDOArtifactsTest(UpdateEbuildWithAFDOArtifactsTest):
-  """Unittests for UploadVettedAFDOArtifacts."""
-
-  @staticmethod
-  def mock_die(message, *args):
-    raise cros_build_lib.DieSystemExit(message % args)
-
-  def setUp(self):
-    self.board = 'board'
-    self.response = toolchain_pb2.VerifyAFDOArtifactsResponse()
-    self.invalid_artifact_type = toolchain_pb2.BENCHMARK_AFDO
-    self.command = self.PatchObject(
-        toolchain_util,
-        'UploadAndPublishVettedAFDOArtifacts',
-        return_value=True)
-    self.PatchObject(cros_build_lib, 'Die', new=self.mock_die)
-
-  def testValidateOnly(self):
-    """Sanity check that a validate only call does not execute any logic."""
-    request = self._GetRequest(
-        build_target=self.board, artifact_type=toolchain_pb2.ORDERFILE)
-    toolchain.UploadVettedAFDOArtifacts(request, self.response,
-                                        self.validate_only_config)
-    self.command.assert_not_called()
-
-  def testMockCall(self):
-    """Test that a mock call does not execute logic, returns mock value."""
-    request = self._GetRequest(
-        build_target=self.board, artifact_type=toolchain_pb2.ORDERFILE)
-    toolchain.UploadVettedAFDOArtifacts(request, self.response,
-                                        self.mock_call_config)
-    self.command.assert_not_called()
-    self.assertEqual(self.response.status, True)
-
-  def testWrongArtifactType(self):
-    """Test passing wrong artifact type."""
-    request = self._GetRequest(
-        build_target=self.board, artifact_type=self.invalid_artifact_type)
-    with self.assertRaises(cros_build_lib.DieSystemExit) as context:
-      toolchain.UploadVettedAFDOArtifacts(request, self.response,
-                                          self.api_config)
-    self.assertIn('artifact_type (%d) must be in' % self.invalid_artifact_type,
-                  str(context.exception))
-
-  def testOrderfileSuccess(self):
-    """Test the command is called correctly with orderfile."""
-    request = self._GetRequest(
-        build_target=self.board, artifact_type=toolchain_pb2.ORDERFILE)
-    toolchain.UploadVettedAFDOArtifacts(request, self.response, self.api_config)
-    self.command.assert_called_once_with('orderfile', self.board)
-
-  def testKernelAFDOSuccess(self):
-    """Test the command is called correctly with kernel afdo."""
-    request = self._GetRequest(
-        build_target=self.board, artifact_type=toolchain_pb2.KERNEL_AFDO)
-    toolchain.UploadVettedAFDOArtifacts(request, self.response, self.api_config)
-    self.command.assert_called_once_with('kernel_afdo', self.board)
-
-  def testChromeAFDOSuccess(self):
-    """Test the command is called correctly with Chrome afdo."""
-    request = self._GetRequest(
-        build_target=self.board, artifact_type=toolchain_pb2.CHROME_AFDO)
-    toolchain.UploadVettedAFDOArtifacts(request, self.response, self.api_config)
-    self.command.assert_called_once_with('chrome_afdo', self.board)
-
 
 class PrepareForBuildTest(cros_test_lib.MockTempDirTestCase,
                           api_config.ApiConfigMixin):
@@ -244,11 +116,11 @@
         chroot=None, sysroot=None, input_artifacts=[
             BuilderConfig.Artifacts.InputArtifactInfo(
                 input_artifact_type=
-                    BuilderConfig.Artifacts.UNVERIFIED_CHROME_LLVM_ORDERFILE,
+                BuilderConfig.Artifacts.UNVERIFIED_CHROME_LLVM_ORDERFILE,
                 input_artifact_gs_locations=['path1', 'path2']),
             BuilderConfig.Artifacts.InputArtifactInfo(
                 input_artifact_type=
-                    BuilderConfig.Artifacts.UNVERIFIED_CHROME_LLVM_ORDERFILE,
+                BuilderConfig.Artifacts.UNVERIFIED_CHROME_LLVM_ORDERFILE,
                 input_artifact_gs_locations=['path3']),
         ],
         profile_info=common_pb2.ArtifactProfileInfo(
@@ -268,11 +140,11 @@
         chroot=None, sysroot=None, input_artifacts=[
             BuilderConfig.Artifacts.InputArtifactInfo(
                 input_artifact_type=
-                    BuilderConfig.Artifacts.UNVERIFIED_CHROME_LLVM_ORDERFILE,
+                BuilderConfig.Artifacts.UNVERIFIED_CHROME_LLVM_ORDERFILE,
                 input_artifact_gs_locations=['path1', 'path2']),
             BuilderConfig.Artifacts.InputArtifactInfo(
                 input_artifact_type=
-                    BuilderConfig.Artifacts.UNVERIFIED_CHROME_LLVM_ORDERFILE,
+                BuilderConfig.Artifacts.UNVERIFIED_CHROME_LLVM_ORDERFILE,
                 input_artifact_gs_locations=['path3']),
         ],
         profile_info=common_pb2.ArtifactProfileInfo(
@@ -297,11 +169,11 @@
         chroot=None, sysroot=None, input_artifacts=[
             BuilderConfig.Artifacts.InputArtifactInfo(
                 input_artifact_type=
-                    BuilderConfig.Artifacts.UNVERIFIED_CHROME_LLVM_ORDERFILE,
+                BuilderConfig.Artifacts.UNVERIFIED_CHROME_LLVM_ORDERFILE,
                 input_artifact_gs_locations=['path1', 'path2']),
             BuilderConfig.Artifacts.InputArtifactInfo(
                 input_artifact_type=
-                    BuilderConfig.Artifacts.UNVERIFIED_CHROME_LLVM_ORDERFILE,
+                BuilderConfig.Artifacts.UNVERIFIED_CHROME_LLVM_ORDERFILE,
                 input_artifact_gs_locations=['path3']),
         ])
     toolchain.PrepareForBuild(request, self.response, self.api_config)
@@ -330,6 +202,8 @@
                 toolchain._Handlers('UnverifiedChromeLlvmOrderfile', self.prep,
                                     self.bundle),
         })
+    osutils.WriteFile(os.path.join(self.tempdir, 'artifact.txt'), 'test')
+    osutils.Touch(os.path.join(self.tempdir, 'empty'))
 
   def _GetRequest(self, artifact_types=None):
     chroot = common_pb2.Chroot(path=self.tempdir)
@@ -358,7 +232,7 @@
   def testSetsArtifactsInfo(self):
     request = self._GetRequest(
         [BuilderConfig.Artifacts.UNVERIFIED_CHROME_LLVM_ORDERFILE])
-    self.bundle.return_value = ['artifact.xz']
+    self.bundle.return_value = ['artifact.txt', 'empty', 'does_not_exist']
     toolchain.BundleArtifacts(request, self.response, self.api_config)
     self.assertEqual(1, len(self.response.artifacts_info))
     self.assertEqual(
diff --git a/api/field_handler.py b/api/field_handler.py
index e05b86b..3078f5e 100644
--- a/api/field_handler.py
+++ b/api/field_handler.py
@@ -91,6 +91,17 @@
   return None
 
 
+def handle_remoteexec(message: protobuf_message.Message):
+  """Find the RemoteexecConfig field, returning the Remoteexec instance."""
+  for descriptor in message.DESCRIPTOR.fields:
+    field = getattr(message, descriptor.name)
+    if isinstance(field, common_pb2.RemoteexecConfig):
+      remoteexec_config = field
+      return controller_util.ParseRemoteexecConfig(remoteexec_config)
+
+  return None
+
+
 class PathHandler(object):
   """Handles copying a file or directory into or out of the chroot."""
 
diff --git a/api/field_handler_unittest.py b/api/field_handler_unittest.py
index b91aaae..a9b9de1 100644
--- a/api/field_handler_unittest.py
+++ b/api/field_handler_unittest.py
@@ -12,6 +12,7 @@
 from chromite.lib import chroot_lib
 from chromite.lib import cros_test_lib
 from chromite.lib import osutils
+from chromite.lib import remoteexec_util
 
 
 class ChrootHandlerTest(cros_test_lib.TestCase):
@@ -73,6 +74,31 @@
     self.assertEqual(empty_chroot, chroot)
 
 
+class HandleRemoteexec(cros_test_lib.TempDirTestCase):
+  """Tests for handling remoteexec."""
+
+  def test_handle_remoteexec(self):
+    """Test handling remoteexec when there is a RemoteexecConfig."""
+    reclient_dir = os.path.join(self.tempdir, 'cipd/rbe')
+    reproxy_cfg_file = os.path.join(self.tempdir,
+                                    'reclient_cfgs/reproxy_config.cfg')
+
+    osutils.SafeMakedirs(reclient_dir)
+    osutils.Touch(reproxy_cfg_file, makedirs=True)
+    remoteexec_config = common_pb2.RemoteexecConfig(
+        reclient_dir=reclient_dir, reproxy_cfg_file=reproxy_cfg_file)
+    message = build_api_test_pb2.TestRequestMessage(
+        remoteexec_config=remoteexec_config)
+
+    expected = remoteexec_util.Remoteexec(reclient_dir, reproxy_cfg_file)
+    self.assertEqual(expected, field_handler.handle_remoteexec(message))
+
+  def test_handle_remoteexec_no_config(self):
+    """Test handling remoteexec when there is no RmoteexecConfig."""
+    message = build_api_test_pb2.TestRequestMessage()
+    self.assertIsNone(field_handler.handle_remoteexec(message))
+
+
 class CopyPathInTest(cros_test_lib.TempDirTestCase):
   """PathHandler tests."""
 
diff --git a/api/gen/chromite/api/android_pb2.py b/api/gen/chromite/api/android_pb2.py
index 2aa47aa..1c3178d 100644
--- a/api/gen/chromite/api/android_pb2.py
+++ b/api/gen/chromite/api/android_pb2.py
@@ -22,7 +22,7 @@
   syntax='proto3',
   serialized_options=b'Z6go.chromium.org/chromiumos/infra/proto/go/chromite/api',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n\x1a\x63hromite/api/android.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x17\x63hromiumos/common.proto\"T\n\x15GetLatestBuildRequest\x12\x1c\n\x14\x61ndroid_build_branch\x18\x02 \x01(\t\x12\x17\n\x0f\x61ndroid_package\x18\x03 \x01(\tJ\x04\x08\x01\x10\x02\"1\n\x16GetLatestBuildResponse\x12\x17\n\x0f\x61ndroid_version\x18\x01 \x01(\t\"\x8c\x02\n\x11MarkStableRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x1b\n\x0ftracking_branch\x18\x02 \x01(\tB\x02\x18\x01\x12\x14\n\x0cpackage_name\x18\x03 \x01(\t\x12\x1c\n\x14\x61ndroid_build_branch\x18\x04 \x01(\t\x12\x17\n\x0f\x61ndroid_version\x18\x05 \x01(\t\x12$\n\x18\x61ndroid_gts_build_branch\x18\x06 \x01(\tB\x02\x18\x01\x12.\n\rbuild_targets\x18\x07 \x03(\x0b\x32\x17.chromiumos.BuildTarget\x12\x13\n\x0bskip_commit\x18\x08 \x01(\x08\"w\n\x12MarkStableResponse\x12\x32\n\x06status\x18\x01 \x01(\x0e\x32\".chromite.api.MarkStableStatusType\x12-\n\x0c\x61ndroid_atom\x18\x02 \x01(\x0b\x32\x17.chromiumos.PackageInfo\"9\n\x13UnpinVersionRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x16\n\x14UnpinVersionResponse*\x9c\x01\n\x14MarkStableStatusType\x12\"\n\x1eMARK_STABLE_STATUS_UNSPECIFIED\x10\x00\x12\x1e\n\x1aMARK_STABLE_STATUS_SUCCESS\x10\x01\x12\x1d\n\x19MARK_STABLE_STATUS_PINNED\x10\x02\x12!\n\x1dMARK_STABLE_STATUS_EARLY_EXIT\x10\x03\x32\xbe\x02\n\x0e\x41ndroidService\x12\x63\n\x0eGetLatestBuild\x12#.chromite.api.GetLatestBuildRequest\x1a$.chromite.api.GetLatestBuildResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x12W\n\nMarkStable\x12\x1f.chromite.api.MarkStableRequest\x1a .chromite.api.MarkStableResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x12]\n\x0cUnpinVersion\x12!.chromite.api.UnpinVersionRequest\x1a\".chromite.api.UnpinVersionResponse\"\x06\xc2\xed\x1a\x02\x10\x01\x1a\x0f\xc2\xed\x1a\x0b\n\x07\x61ndroid\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
+  serialized_pb=b'\n\x1a\x63hromite/api/android.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x17\x63hromiumos/common.proto\"T\n\x15GetLatestBuildRequest\x12\x1c\n\x14\x61ndroid_build_branch\x18\x02 \x01(\t\x12\x17\n\x0f\x61ndroid_package\x18\x03 \x01(\tJ\x04\x08\x01\x10\x02\"1\n\x16GetLatestBuildResponse\x12\x17\n\x0f\x61ndroid_version\x18\x01 \x01(\t\"\x8c\x02\n\x11MarkStableRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x1b\n\x0ftracking_branch\x18\x02 \x01(\tB\x02\x18\x01\x12\x14\n\x0cpackage_name\x18\x03 \x01(\t\x12\x1c\n\x14\x61ndroid_build_branch\x18\x04 \x01(\t\x12\x17\n\x0f\x61ndroid_version\x18\x05 \x01(\t\x12$\n\x18\x61ndroid_gts_build_branch\x18\x06 \x01(\tB\x02\x18\x01\x12.\n\rbuild_targets\x18\x07 \x03(\x0b\x32\x17.chromiumos.BuildTarget\x12\x13\n\x0bskip_commit\x18\x08 \x01(\x08\"w\n\x12MarkStableResponse\x12\x32\n\x06status\x18\x01 \x01(\x0e\x32\".chromite.api.MarkStableStatusType\x12-\n\x0c\x61ndroid_atom\x18\x02 \x01(\x0b\x32\x17.chromiumos.PackageInfo\"9\n\x13UnpinVersionRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x16\n\x14UnpinVersionResponse\"D\n\x10WriteLKGBRequest\x12\x17\n\x0f\x61ndroid_package\x18\x01 \x01(\t\x12\x17\n\x0f\x61ndroid_version\x18\x02 \x01(\t\"+\n\x11WriteLKGBResponse\x12\x16\n\x0emodified_files\x18\x01 \x03(\t*\x9c\x01\n\x14MarkStableStatusType\x12\"\n\x1eMARK_STABLE_STATUS_UNSPECIFIED\x10\x00\x12\x1e\n\x1aMARK_STABLE_STATUS_SUCCESS\x10\x01\x12\x1d\n\x19MARK_STABLE_STATUS_PINNED\x10\x02\x12!\n\x1dMARK_STABLE_STATUS_EARLY_EXIT\x10\x03\x32\x94\x03\n\x0e\x41ndroidService\x12\x63\n\x0eGetLatestBuild\x12#.chromite.api.GetLatestBuildRequest\x1a$.chromite.api.GetLatestBuildResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x12W\n\nMarkStable\x12\x1f.chromite.api.MarkStableRequest\x1a .chromite.api.MarkStableResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x12]\n\x0cUnpinVersion\x12!.chromite.api.UnpinVersionRequest\x1a\".chromite.api.UnpinVersionResponse\"\x06\xc2\xed\x1a\x02\x10\x01\x12T\n\tWriteLKGB\x12\x1e.chromite.api.WriteLKGBRequest\x1a\x1f.chromite.api.WriteLKGBResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x1a\x0f\xc2\xed\x1a\x0b\n\x07\x61ndroid\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
   ,
   dependencies=[chromite_dot_api_dot_build__api__pb2.DESCRIPTOR,chromiumos_dot_common__pb2.DESCRIPTOR,])
 
@@ -56,8 +56,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=712,
-  serialized_end=868,
+  serialized_start=827,
+  serialized_end=983,
 )
 _sym_db.RegisterEnumDescriptor(_MARKSTABLESTATUSTYPE)
 
@@ -316,6 +316,77 @@
   serialized_end=709,
 )
 
+
+_WRITELKGBREQUEST = _descriptor.Descriptor(
+  name='WriteLKGBRequest',
+  full_name='chromite.api.WriteLKGBRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='android_package', full_name='chromite.api.WriteLKGBRequest.android_package', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='android_version', full_name='chromite.api.WriteLKGBRequest.android_version', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=711,
+  serialized_end=779,
+)
+
+
+_WRITELKGBRESPONSE = _descriptor.Descriptor(
+  name='WriteLKGBResponse',
+  full_name='chromite.api.WriteLKGBResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='modified_files', full_name='chromite.api.WriteLKGBResponse.modified_files', index=0,
+      number=1, type=9, cpp_type=9, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=781,
+  serialized_end=824,
+)
+
 _MARKSTABLEREQUEST.fields_by_name['chroot'].message_type = chromiumos_dot_common__pb2._CHROOT
 _MARKSTABLEREQUEST.fields_by_name['build_targets'].message_type = chromiumos_dot_common__pb2._BUILDTARGET
 _MARKSTABLERESPONSE.fields_by_name['status'].enum_type = _MARKSTABLESTATUSTYPE
@@ -327,6 +398,8 @@
 DESCRIPTOR.message_types_by_name['MarkStableResponse'] = _MARKSTABLERESPONSE
 DESCRIPTOR.message_types_by_name['UnpinVersionRequest'] = _UNPINVERSIONREQUEST
 DESCRIPTOR.message_types_by_name['UnpinVersionResponse'] = _UNPINVERSIONRESPONSE
+DESCRIPTOR.message_types_by_name['WriteLKGBRequest'] = _WRITELKGBREQUEST
+DESCRIPTOR.message_types_by_name['WriteLKGBResponse'] = _WRITELKGBRESPONSE
 DESCRIPTOR.enum_types_by_name['MarkStableStatusType'] = _MARKSTABLESTATUSTYPE
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
@@ -372,6 +445,20 @@
   })
 _sym_db.RegisterMessage(UnpinVersionResponse)
 
+WriteLKGBRequest = _reflection.GeneratedProtocolMessageType('WriteLKGBRequest', (_message.Message,), {
+  'DESCRIPTOR' : _WRITELKGBREQUEST,
+  '__module__' : 'chromite.api.android_pb2'
+  # @@protoc_insertion_point(class_scope:chromite.api.WriteLKGBRequest)
+  })
+_sym_db.RegisterMessage(WriteLKGBRequest)
+
+WriteLKGBResponse = _reflection.GeneratedProtocolMessageType('WriteLKGBResponse', (_message.Message,), {
+  'DESCRIPTOR' : _WRITELKGBRESPONSE,
+  '__module__' : 'chromite.api.android_pb2'
+  # @@protoc_insertion_point(class_scope:chromite.api.WriteLKGBResponse)
+  })
+_sym_db.RegisterMessage(WriteLKGBResponse)
+
 
 DESCRIPTOR._options = None
 _MARKSTABLEREQUEST.fields_by_name['tracking_branch']._options = None
@@ -384,8 +471,8 @@
   index=0,
   serialized_options=b'\302\355\032\013\n\007android\020\001',
   create_key=_descriptor._internal_create_key,
-  serialized_start=871,
-  serialized_end=1189,
+  serialized_start=986,
+  serialized_end=1390,
   methods=[
   _descriptor.MethodDescriptor(
     name='GetLatestBuild',
@@ -417,6 +504,16 @@
     serialized_options=b'\302\355\032\002\020\001',
     create_key=_descriptor._internal_create_key,
   ),
+  _descriptor.MethodDescriptor(
+    name='WriteLKGB',
+    full_name='chromite.api.AndroidService.WriteLKGB',
+    index=3,
+    containing_service=None,
+    input_type=_WRITELKGBREQUEST,
+    output_type=_WRITELKGBRESPONSE,
+    serialized_options=b'\302\355\032\002\020\002',
+    create_key=_descriptor._internal_create_key,
+  ),
 ])
 _sym_db.RegisterServiceDescriptor(_ANDROIDSERVICE)
 
diff --git a/api/gen/chromite/api/artifacts_pb2.py b/api/gen/chromite/api/artifacts_pb2.py
index ce6dc87..63f4e1d 100644
--- a/api/gen/chromite/api/artifacts_pb2.py
+++ b/api/gen/chromite/api/artifacts_pb2.py
@@ -22,7 +22,7 @@
   syntax='proto3',
   serialized_options=b'Z6go.chromium.org/chromiumos/infra/proto/go/chromite/api',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n\x1c\x63hromite/api/artifacts.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x1a\x63hromite/api/sysroot.proto\x1a\x17\x63hromiumos/common.proto\"\x18\n\x08\x41rtifact\x12\x0c\n\x04path\x18\x01 \x01(\t\"W\n\x0b\x44ockerBuild\x12\x12\n\nimage_name\x18\x01 \x01(\t\x12\x18\n\x10\x64ocker_file_path\x18\x02 \x01(\t\x12\x1a\n\x12\x62uild_context_path\x18\x03 \x01(\t\"\xb3\x01\n\x17PrepareForBuildResponse\x12M\n\x0f\x62uild_relevance\x18\x01 \x01(\x0e\x32\x34.chromite.api.PrepareForBuildResponse.BuildRelevance\"I\n\x0e\x42uildRelevance\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\n\n\x06NEEDED\x10\x01\x12\x0b\n\x07UNKNOWN\x10\x02\x12\r\n\tPOINTLESS\x10\x03\"\xb6\x01\n\x11\x42uildSetupRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\x35\n\rartifact_info\x18\x03 \x01(\x0b\x32\x1e.chromiumos.ArtifactsByService\x12\x1e\n\x16\x66orced_build_relevance\x18\x04 \x01(\x08\"\xa9\x01\n\x12\x42uildSetupResponse\x12H\n\x0f\x62uild_relevance\x18\x01 \x01(\x0e\x32/.chromite.api.BuildSetupResponse.BuildRelevance\"I\n\x0e\x42uildRelevance\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\n\n\x06NEEDED\x10\x01\x12\x0b\n\x07UNKNOWN\x10\x02\x12\r\n\tPOINTLESS\x10\x03\"\xbc\x01\n\nGetRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\x35\n\rartifact_info\x18\x03 \x01(\x0b\x32\x1e.chromiumos.ArtifactsByService\x12+\n\x0bresult_path\x18\x04 \x01(\x0b\x32\x16.chromiumos.ResultPath\"H\n\x0bGetResponse\x12\x39\n\tartifacts\x18\x01 \x01(\x0b\x32&.chromiumos.UploadedArtifactsByService\"\xdc\x01\n\x16\x42undleArtifactsRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\x35\n\rartifact_info\x18\x03 \x01(\x0b\x32\x1e.chromiumos.ArtifactsByService\x12\x12\n\noutput_dir\x18\x04 \x01(\t\x12+\n\x0bresult_path\x18\x05 \x01(\x0b\x32\x16.chromiumos.ResultPath\"T\n\x17\x42undleArtifactsResponse\x12\x39\n\tartifacts\x18\x01 \x01(\x0b\x32&.chromiumos.UploadedArtifactsByService\"\x9e\x01\n\rBundleRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x12\n\noutput_dir\x18\x02 \x01(\t\x12\"\n\x06\x63hroot\x18\x03 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x04 \x01(\x0b\x32\x15.chromite.api.Sysroot\"m\n\x0e\x42undleResponse\x12)\n\tartifacts\x18\x01 \x03(\x0b\x32\x16.chromite.api.Artifact\x12\x30\n\rdocker_builds\x18\x02 \x03(\x0b\x32\x19.chromite.api.DockerBuild\"\x90\x01\n\x14\x42undleVmFilesRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\x18\n\x10test_results_dir\x18\x03 \x01(\t\x12\x12\n\noutput_dir\x18\x04 \x01(\t\"\xb5\x01\n\x17\x42undleChromeAFDORequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x12\n\noutput_dir\x18\x03 \x01(\t\x12\x33\n\rartifact_type\x18\x04 \x01(\x0e\x32\x1c.chromiumos.AFDOArtifactType\"h\n\x1aPinnedGuestImageUriRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\"\xa3\x01\n\x1bPinnedGuestImageUriResponse\x12Q\n\rpinned_images\x18\x01 \x03(\x0b\x32:.chromite.api.PinnedGuestImageUriResponse.PinnedGuestImage\x1a\x31\n\x10PinnedGuestImage\x12\x10\n\x08\x66ilename\x18\x01 \x01(\t\x12\x0b\n\x03uri\x18\x02 \x01(\t\"b\n\x14\x46\x65tchMetadataRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\"B\n\x15\x46\x65tchMetadataResponse\x12)\n\tfilepaths\x18\x01 \x03(\x0b\x32\x16.chromiumos.ResultPath2\xad\r\n\x10\x41rtifactsService\x12O\n\nBuildSetup\x12\x1f.chromite.api.BuildSetupRequest\x1a .chromite.api.BuildSetupResponse\x12:\n\x03Get\x12\x18.chromite.api.GetRequest\x1a\x19.chromite.api.GetResponse\x12p\n\x19\x46\x65tchPinnedGuestImageUris\x12(.chromite.api.PinnedGuestImageUriRequest\x1a).chromite.api.PinnedGuestImageUriResponse\x12X\n\rFetchMetadata\x12\".chromite.api.FetchMetadataRequest\x1a#.chromite.api.FetchMetadataResponse\x12P\n\x13\x42undleAutotestFiles\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12Q\n\x14\x42undleChromeOSConfig\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12O\n\x12\x42undleDebugSymbols\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12M\n\x10\x42undleEbuildLogs\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12K\n\x0e\x42undleFirmware\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12P\n\x13\x42undleImageArchives\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12K\n\x0e\x42undleImageZip\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12\x64\n\x1d\x42undleAFDOGenerationArtifacts\x12%.chromite.api.BundleChromeAFDORequest\x1a\x1c.chromite.api.BundleResponse\x12T\n\x17\x42undlePinnedGuestImages\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12X\n\x1b\x42undleSimpleChromeArtifacts\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12L\n\x0f\x42undleTastFiles\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12U\n\x18\x42undleTestUpdatePayloads\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12Q\n\rBundleVmFiles\x12\".chromite.api.BundleVmFilesRequest\x1a\x1c.chromite.api.BundleResponse\x12L\n\x0f\x45xportCpeReport\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12Q\n\x14\x42undleFpmcuUnittests\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12M\n\x10\x42undleGceTarball\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x1a\x11\xc2\xed\x1a\r\n\tartifacts\x10\x02\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
+  serialized_pb=b'\n\x1c\x63hromite/api/artifacts.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x1a\x63hromite/api/sysroot.proto\x1a\x17\x63hromiumos/common.proto\"\x18\n\x08\x41rtifact\x12\x0c\n\x04path\x18\x01 \x01(\t\"W\n\x0b\x44ockerBuild\x12\x12\n\nimage_name\x18\x01 \x01(\t\x12\x18\n\x10\x64ocker_file_path\x18\x02 \x01(\t\x12\x1a\n\x12\x62uild_context_path\x18\x03 \x01(\t\"\xb3\x01\n\x17PrepareForBuildResponse\x12M\n\x0f\x62uild_relevance\x18\x01 \x01(\x0e\x32\x34.chromite.api.PrepareForBuildResponse.BuildRelevance\"I\n\x0e\x42uildRelevance\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\n\n\x06NEEDED\x10\x01\x12\x0b\n\x07UNKNOWN\x10\x02\x12\r\n\tPOINTLESS\x10\x03\"\xb6\x01\n\x11\x42uildSetupRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\x35\n\rartifact_info\x18\x03 \x01(\x0b\x32\x1e.chromiumos.ArtifactsByService\x12\x1e\n\x16\x66orced_build_relevance\x18\x04 \x01(\x08\"\xa9\x01\n\x12\x42uildSetupResponse\x12H\n\x0f\x62uild_relevance\x18\x01 \x01(\x0e\x32/.chromite.api.BuildSetupResponse.BuildRelevance\"I\n\x0e\x42uildRelevance\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\n\n\x06NEEDED\x10\x01\x12\x0b\n\x07UNKNOWN\x10\x02\x12\r\n\tPOINTLESS\x10\x03\"\xbc\x01\n\nGetRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\x35\n\rartifact_info\x18\x03 \x01(\x0b\x32\x1e.chromiumos.ArtifactsByService\x12+\n\x0bresult_path\x18\x04 \x01(\x0b\x32\x16.chromiumos.ResultPath\"H\n\x0bGetResponse\x12\x39\n\tartifacts\x18\x01 \x01(\x0b\x32&.chromiumos.UploadedArtifactsByService\"\xdc\x01\n\x16\x42undleArtifactsRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\x35\n\rartifact_info\x18\x03 \x01(\x0b\x32\x1e.chromiumos.ArtifactsByService\x12\x12\n\noutput_dir\x18\x04 \x01(\t\x12+\n\x0bresult_path\x18\x05 \x01(\x0b\x32\x16.chromiumos.ResultPath\"T\n\x17\x42undleArtifactsResponse\x12\x39\n\tartifacts\x18\x01 \x01(\x0b\x32&.chromiumos.UploadedArtifactsByService\"\x9e\x01\n\rBundleRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x12\n\noutput_dir\x18\x02 \x01(\t\x12\"\n\x06\x63hroot\x18\x03 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x04 \x01(\x0b\x32\x15.chromite.api.Sysroot\"m\n\x0e\x42undleResponse\x12)\n\tartifacts\x18\x01 \x03(\x0b\x32\x16.chromite.api.Artifact\x12\x30\n\rdocker_builds\x18\x02 \x03(\x0b\x32\x19.chromite.api.DockerBuild\"\x90\x01\n\x14\x42undleVmFilesRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\x18\n\x10test_results_dir\x18\x03 \x01(\t\x12\x12\n\noutput_dir\x18\x04 \x01(\t\"h\n\x1aPinnedGuestImageUriRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\"\xa3\x01\n\x1bPinnedGuestImageUriResponse\x12Q\n\rpinned_images\x18\x01 \x03(\x0b\x32:.chromite.api.PinnedGuestImageUriResponse.PinnedGuestImage\x1a\x31\n\x10PinnedGuestImage\x12\x10\n\x08\x66ilename\x18\x01 \x01(\t\x12\x0b\n\x03uri\x18\x02 \x01(\t\"b\n\x14\x46\x65tchMetadataRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\"B\n\x15\x46\x65tchMetadataResponse\x12)\n\tfilepaths\x18\x01 \x03(\x0b\x32\x16.chromiumos.ResultPath2\xc7\x0c\n\x10\x41rtifactsService\x12O\n\nBuildSetup\x12\x1f.chromite.api.BuildSetupRequest\x1a .chromite.api.BuildSetupResponse\x12:\n\x03Get\x12\x18.chromite.api.GetRequest\x1a\x19.chromite.api.GetResponse\x12p\n\x19\x46\x65tchPinnedGuestImageUris\x12(.chromite.api.PinnedGuestImageUriRequest\x1a).chromite.api.PinnedGuestImageUriResponse\x12X\n\rFetchMetadata\x12\".chromite.api.FetchMetadataRequest\x1a#.chromite.api.FetchMetadataResponse\x12P\n\x13\x42undleAutotestFiles\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12Q\n\x14\x42undleChromeOSConfig\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12O\n\x12\x42undleDebugSymbols\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12M\n\x10\x42undleEbuildLogs\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12K\n\x0e\x42undleFirmware\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12P\n\x13\x42undleImageArchives\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12K\n\x0e\x42undleImageZip\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12T\n\x17\x42undlePinnedGuestImages\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12X\n\x1b\x42undleSimpleChromeArtifacts\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12L\n\x0f\x42undleTastFiles\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12U\n\x18\x42undleTestUpdatePayloads\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12Q\n\rBundleVmFiles\x12\".chromite.api.BundleVmFilesRequest\x1a\x1c.chromite.api.BundleResponse\x12L\n\x0f\x45xportCpeReport\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12Q\n\x14\x42undleFpmcuUnittests\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12M\n\x10\x42undleGceTarball\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x1a\x11\xc2\xed\x1a\r\n\tartifacts\x10\x02\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
   ,
   dependencies=[chromite_dot_api_dot_build__api__pb2.DESCRIPTOR,chromite_dot_api_dot_sysroot__pb2.DESCRIPTOR,chromiumos_dot_common__pb2.DESCRIPTOR,])
 
@@ -618,59 +618,6 @@
 )
 
 
-_BUNDLECHROMEAFDOREQUEST = _descriptor.Descriptor(
-  name='BundleChromeAFDORequest',
-  full_name='chromite.api.BundleChromeAFDORequest',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  create_key=_descriptor._internal_create_key,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='chroot', full_name='chromite.api.BundleChromeAFDORequest.chroot', index=0,
-      number=1, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='build_target', full_name='chromite.api.BundleChromeAFDORequest.build_target', index=1,
-      number=2, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='output_dir', full_name='chromite.api.BundleChromeAFDORequest.output_dir', index=2,
-      number=3, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=b"".decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='artifact_type', full_name='chromite.api.BundleChromeAFDORequest.artifact_type', index=3,
-      number=4, type=14, cpp_type=8, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1777,
-  serialized_end=1958,
-)
-
-
 _PINNEDGUESTIMAGEURIREQUEST = _descriptor.Descriptor(
   name='PinnedGuestImageUriRequest',
   full_name='chromite.api.PinnedGuestImageUriRequest',
@@ -705,8 +652,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1960,
-  serialized_end=2064,
+  serialized_start=1776,
+  serialized_end=1880,
 )
 
 
@@ -744,8 +691,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2181,
-  serialized_end=2230,
+  serialized_start=1997,
+  serialized_end=2046,
 )
 
 _PINNEDGUESTIMAGEURIRESPONSE = _descriptor.Descriptor(
@@ -775,8 +722,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2067,
-  serialized_end=2230,
+  serialized_start=1883,
+  serialized_end=2046,
 )
 
 
@@ -814,8 +761,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2232,
-  serialized_end=2330,
+  serialized_start=2048,
+  serialized_end=2146,
 )
 
 
@@ -846,8 +793,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2332,
-  serialized_end=2398,
+  serialized_start=2148,
+  serialized_end=2214,
 )
 
 _PREPAREFORBUILDRESPONSE.fields_by_name['build_relevance'].enum_type = _PREPAREFORBUILDRESPONSE_BUILDRELEVANCE
@@ -874,9 +821,6 @@
 _BUNDLERESPONSE.fields_by_name['docker_builds'].message_type = _DOCKERBUILD
 _BUNDLEVMFILESREQUEST.fields_by_name['chroot'].message_type = chromiumos_dot_common__pb2._CHROOT
 _BUNDLEVMFILESREQUEST.fields_by_name['sysroot'].message_type = chromite_dot_api_dot_sysroot__pb2._SYSROOT
-_BUNDLECHROMEAFDOREQUEST.fields_by_name['chroot'].message_type = chromiumos_dot_common__pb2._CHROOT
-_BUNDLECHROMEAFDOREQUEST.fields_by_name['build_target'].message_type = chromiumos_dot_common__pb2._BUILDTARGET
-_BUNDLECHROMEAFDOREQUEST.fields_by_name['artifact_type'].enum_type = chromiumos_dot_common__pb2._AFDOARTIFACTTYPE
 _PINNEDGUESTIMAGEURIREQUEST.fields_by_name['chroot'].message_type = chromiumos_dot_common__pb2._CHROOT
 _PINNEDGUESTIMAGEURIREQUEST.fields_by_name['sysroot'].message_type = chromite_dot_api_dot_sysroot__pb2._SYSROOT
 _PINNEDGUESTIMAGEURIRESPONSE_PINNEDGUESTIMAGE.containing_type = _PINNEDGUESTIMAGEURIRESPONSE
@@ -896,7 +840,6 @@
 DESCRIPTOR.message_types_by_name['BundleRequest'] = _BUNDLEREQUEST
 DESCRIPTOR.message_types_by_name['BundleResponse'] = _BUNDLERESPONSE
 DESCRIPTOR.message_types_by_name['BundleVmFilesRequest'] = _BUNDLEVMFILESREQUEST
-DESCRIPTOR.message_types_by_name['BundleChromeAFDORequest'] = _BUNDLECHROMEAFDOREQUEST
 DESCRIPTOR.message_types_by_name['PinnedGuestImageUriRequest'] = _PINNEDGUESTIMAGEURIREQUEST
 DESCRIPTOR.message_types_by_name['PinnedGuestImageUriResponse'] = _PINNEDGUESTIMAGEURIRESPONSE
 DESCRIPTOR.message_types_by_name['FetchMetadataRequest'] = _FETCHMETADATAREQUEST
@@ -987,13 +930,6 @@
   })
 _sym_db.RegisterMessage(BundleVmFilesRequest)
 
-BundleChromeAFDORequest = _reflection.GeneratedProtocolMessageType('BundleChromeAFDORequest', (_message.Message,), {
-  'DESCRIPTOR' : _BUNDLECHROMEAFDOREQUEST,
-  '__module__' : 'chromite.api.artifacts_pb2'
-  # @@protoc_insertion_point(class_scope:chromite.api.BundleChromeAFDORequest)
-  })
-_sym_db.RegisterMessage(BundleChromeAFDORequest)
-
 PinnedGuestImageUriRequest = _reflection.GeneratedProtocolMessageType('PinnedGuestImageUriRequest', (_message.Message,), {
   'DESCRIPTOR' : _PINNEDGUESTIMAGEURIREQUEST,
   '__module__' : 'chromite.api.artifacts_pb2'
@@ -1040,8 +976,8 @@
   index=0,
   serialized_options=b'\302\355\032\r\n\tartifacts\020\002',
   create_key=_descriptor._internal_create_key,
-  serialized_start=2401,
-  serialized_end=4110,
+  serialized_start=2217,
+  serialized_end=3824,
   methods=[
   _descriptor.MethodDescriptor(
     name='BuildSetup',
@@ -1154,19 +1090,9 @@
     create_key=_descriptor._internal_create_key,
   ),
   _descriptor.MethodDescriptor(
-    name='BundleAFDOGenerationArtifacts',
-    full_name='chromite.api.ArtifactsService.BundleAFDOGenerationArtifacts',
-    index=11,
-    containing_service=None,
-    input_type=_BUNDLECHROMEAFDOREQUEST,
-    output_type=_BUNDLERESPONSE,
-    serialized_options=None,
-    create_key=_descriptor._internal_create_key,
-  ),
-  _descriptor.MethodDescriptor(
     name='BundlePinnedGuestImages',
     full_name='chromite.api.ArtifactsService.BundlePinnedGuestImages',
-    index=12,
+    index=11,
     containing_service=None,
     input_type=_BUNDLEREQUEST,
     output_type=_BUNDLERESPONSE,
@@ -1176,7 +1102,7 @@
   _descriptor.MethodDescriptor(
     name='BundleSimpleChromeArtifacts',
     full_name='chromite.api.ArtifactsService.BundleSimpleChromeArtifacts',
-    index=13,
+    index=12,
     containing_service=None,
     input_type=_BUNDLEREQUEST,
     output_type=_BUNDLERESPONSE,
@@ -1186,7 +1112,7 @@
   _descriptor.MethodDescriptor(
     name='BundleTastFiles',
     full_name='chromite.api.ArtifactsService.BundleTastFiles',
-    index=14,
+    index=13,
     containing_service=None,
     input_type=_BUNDLEREQUEST,
     output_type=_BUNDLERESPONSE,
@@ -1196,7 +1122,7 @@
   _descriptor.MethodDescriptor(
     name='BundleTestUpdatePayloads',
     full_name='chromite.api.ArtifactsService.BundleTestUpdatePayloads',
-    index=15,
+    index=14,
     containing_service=None,
     input_type=_BUNDLEREQUEST,
     output_type=_BUNDLERESPONSE,
@@ -1206,7 +1132,7 @@
   _descriptor.MethodDescriptor(
     name='BundleVmFiles',
     full_name='chromite.api.ArtifactsService.BundleVmFiles',
-    index=16,
+    index=15,
     containing_service=None,
     input_type=_BUNDLEVMFILESREQUEST,
     output_type=_BUNDLERESPONSE,
@@ -1216,7 +1142,7 @@
   _descriptor.MethodDescriptor(
     name='ExportCpeReport',
     full_name='chromite.api.ArtifactsService.ExportCpeReport',
-    index=17,
+    index=16,
     containing_service=None,
     input_type=_BUNDLEREQUEST,
     output_type=_BUNDLERESPONSE,
@@ -1226,7 +1152,7 @@
   _descriptor.MethodDescriptor(
     name='BundleFpmcuUnittests',
     full_name='chromite.api.ArtifactsService.BundleFpmcuUnittests',
-    index=18,
+    index=17,
     containing_service=None,
     input_type=_BUNDLEREQUEST,
     output_type=_BUNDLERESPONSE,
@@ -1236,7 +1162,7 @@
   _descriptor.MethodDescriptor(
     name='BundleGceTarball',
     full_name='chromite.api.ArtifactsService.BundleGceTarball',
-    index=19,
+    index=18,
     containing_service=None,
     input_type=_BUNDLEREQUEST,
     output_type=_BUNDLERESPONSE,
diff --git a/api/gen/chromite/api/build_api_test_pb2.py b/api/gen/chromite/api/build_api_test_pb2.py
index 578a75c..f561603 100644
--- a/api/gen/chromite/api/build_api_test_pb2.py
+++ b/api/gen/chromite/api/build_api_test_pb2.py
@@ -23,7 +23,7 @@
   syntax='proto3',
   serialized_options=b'Z6go.chromium.org/chromiumos/infra/proto/go/chromite/api',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n!chromite/api/build_api_test.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x17\x63hromiumos/common.proto\x1a\x18\x63hromiumos/metrics.proto\",\n\nNestedPath\x12\x1e\n\x04path\x18\x01 \x01(\x0b\x32\x10.chromiumos.Path\"f\n\x11MultiFieldMessage\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0c\n\x04\x66lag\x18\x03 \x01(\x08\x12)\n\ttest_enum\x18\x04 \x01(\x0e\x32\x16.chromite.api.TestEnum\"\xc9\x04\n\x12TestRequestMessage\x12\n\n\x02id\x18\x01 \x01(\t\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x1e\n\x04path\x18\x03 \x01(\x0b\x32\x10.chromiumos.Path\x12&\n\x0c\x61nother_path\x18\x04 \x01(\x0b\x32\x10.chromiumos.Path\x12-\n\x0bnested_path\x18\x05 \x01(\x0b\x32\x18.chromite.api.NestedPath\x12+\n\x0bresult_path\x18\x06 \x01(\x0b\x32\x16.chromiumos.ResultPath\x12-\n\x0c\x62uild_target\x18\x07 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12.\n\rbuild_targets\x18\x08 \x03(\x0b\x32\x17.chromiumos.BuildTarget\x12)\n\nsynced_dir\x18\t \x01(\x0b\x32\x15.chromiumos.SyncedDir\x12*\n\x0bsynced_dirs\x18\n \x03(\x0b\x32\x15.chromiumos.SyncedDir\x12\x31\n\x08messages\x18\x0b \x03(\x0b\x32\x1f.chromite.api.MultiFieldMessage\x12)\n\ttest_enum\x18\x0c \x01(\x0e\x32\x16.chromite.api.TestEnum\x12*\n\ntest_enums\x18\r \x03(\x0e\x32\x16.chromite.api.TestEnum\x12\x0e\n\x06number\x18\x0e \x01(\x05\x12\x0f\n\x07numbers\x18\x0f \x03(\x05\"\xc8\x01\n\x11TestResultMessage\x12\x0e\n\x06result\x18\x01 \x01(\t\x12\"\n\x08\x61rtifact\x18\x02 \x01(\x0b\x32\x10.chromiumos.Path\x12\x31\n\x0fnested_artifact\x18\x03 \x01(\x0b\x32\x18.chromite.api.NestedPath\x12#\n\tartifacts\x18\x04 \x03(\x0b\x32\x10.chromiumos.Path\x12\'\n\x06\x65vents\x18\x05 \x03(\x0b\x32\x17.chromiumos.MetricEvent*^\n\x08TestEnum\x12\x19\n\x15TEST_ENUM_UNSPECIFIED\x10\x00\x12\x11\n\rTEST_ENUM_FOO\x10\x01\x12\x11\n\rTEST_ENUM_BAR\x10\x02\x12\x11\n\rTEST_ENUM_BAZ\x10\x03\x32\xc0\x02\n\x0eTestApiService\x12V\n\x11InputOutputMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\x12\x65\n\rRenamedMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\"\x11\xc2\xed\x1a\r\n\x0b\x43orrectName\x12Y\n\x0cHiddenMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\"\x06\xc2\xed\x1a\x02\x18\x02\x1a\x14\xc2\xed\x1a\x10\n\x0e\x62uild_api_test2\xf9\x01\n\x16InsideChrootApiService\x12^\n\x19InsideServiceInsideMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\x12g\n\x1aInsideServiceOutsideMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\"\x06\xc2\xed\x1a\x02\x10\x02\x1a\x16\xc2\xed\x1a\x12\n\x0e\x62uild_api_test\x10\x01\x32\xfc\x01\n\x17OutsideChrootApiService\x12`\n\x1bOutsideServiceOutsideMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\x12g\n\x1aOutsideServiceInsideMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\"\x06\xc2\xed\x1a\x02\x10\x01\x1a\x16\xc2\xed\x1a\x12\n\x0e\x62uild_api_test\x10\x02\x32|\n\rHiddenService\x12Q\n\x0cHiddenMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\x1a\x18\xc2\xed\x1a\x14\n\x0e\x62uild_api_test\x10\x02\x18\x02\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
+  serialized_pb=b'\n!chromite/api/build_api_test.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x17\x63hromiumos/common.proto\x1a\x18\x63hromiumos/metrics.proto\",\n\nNestedPath\x12\x1e\n\x04path\x18\x01 \x01(\x0b\x32\x10.chromiumos.Path\"f\n\x11MultiFieldMessage\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0c\n\x04\x66lag\x18\x03 \x01(\x08\x12)\n\ttest_enum\x18\x04 \x01(\x0e\x32\x16.chromite.api.TestEnum\"\x82\x05\n\x12TestRequestMessage\x12\n\n\x02id\x18\x01 \x01(\t\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x1e\n\x04path\x18\x03 \x01(\x0b\x32\x10.chromiumos.Path\x12&\n\x0c\x61nother_path\x18\x04 \x01(\x0b\x32\x10.chromiumos.Path\x12-\n\x0bnested_path\x18\x05 \x01(\x0b\x32\x18.chromite.api.NestedPath\x12+\n\x0bresult_path\x18\x06 \x01(\x0b\x32\x16.chromiumos.ResultPath\x12-\n\x0c\x62uild_target\x18\x07 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12.\n\rbuild_targets\x18\x08 \x03(\x0b\x32\x17.chromiumos.BuildTarget\x12)\n\nsynced_dir\x18\t \x01(\x0b\x32\x15.chromiumos.SyncedDir\x12*\n\x0bsynced_dirs\x18\n \x03(\x0b\x32\x15.chromiumos.SyncedDir\x12\x31\n\x08messages\x18\x0b \x03(\x0b\x32\x1f.chromite.api.MultiFieldMessage\x12)\n\ttest_enum\x18\x0c \x01(\x0e\x32\x16.chromite.api.TestEnum\x12*\n\ntest_enums\x18\r \x03(\x0e\x32\x16.chromite.api.TestEnum\x12\x0e\n\x06number\x18\x0e \x01(\x05\x12\x0f\n\x07numbers\x18\x0f \x03(\x05\x12\x37\n\x11remoteexec_config\x18\x10 \x01(\x0b\x32\x1c.chromiumos.RemoteexecConfig\"\xc8\x01\n\x11TestResultMessage\x12\x0e\n\x06result\x18\x01 \x01(\t\x12\"\n\x08\x61rtifact\x18\x02 \x01(\x0b\x32\x10.chromiumos.Path\x12\x31\n\x0fnested_artifact\x18\x03 \x01(\x0b\x32\x18.chromite.api.NestedPath\x12#\n\tartifacts\x18\x04 \x03(\x0b\x32\x10.chromiumos.Path\x12\'\n\x06\x65vents\x18\x05 \x03(\x0b\x32\x17.chromiumos.MetricEvent*^\n\x08TestEnum\x12\x19\n\x15TEST_ENUM_UNSPECIFIED\x10\x00\x12\x11\n\rTEST_ENUM_FOO\x10\x01\x12\x11\n\rTEST_ENUM_BAR\x10\x02\x12\x11\n\rTEST_ENUM_BAZ\x10\x03\x32\xc0\x02\n\x0eTestApiService\x12V\n\x11InputOutputMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\x12\x65\n\rRenamedMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\"\x11\xc2\xed\x1a\r\n\x0b\x43orrectName\x12Y\n\x0cHiddenMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\"\x06\xc2\xed\x1a\x02\x18\x02\x1a\x14\xc2\xed\x1a\x10\n\x0e\x62uild_api_test2\xf9\x01\n\x16InsideChrootApiService\x12^\n\x19InsideServiceInsideMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\x12g\n\x1aInsideServiceOutsideMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\"\x06\xc2\xed\x1a\x02\x10\x02\x1a\x16\xc2\xed\x1a\x12\n\x0e\x62uild_api_test\x10\x01\x32\xfc\x01\n\x17OutsideChrootApiService\x12`\n\x1bOutsideServiceOutsideMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\x12g\n\x1aOutsideServiceInsideMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\"\x06\xc2\xed\x1a\x02\x10\x01\x1a\x16\xc2\xed\x1a\x12\n\x0e\x62uild_api_test\x10\x02\x32|\n\rHiddenService\x12Q\n\x0cHiddenMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\x1a\x18\xc2\xed\x1a\x14\n\x0e\x62uild_api_test\x10\x02\x18\x02\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
   ,
   dependencies=[chromite_dot_api_dot_build__api__pb2.DESCRIPTOR,chromiumos_dot_common__pb2.DESCRIPTOR,chromiumos_dot_metrics__pb2.DESCRIPTOR,])
 
@@ -57,8 +57,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1073,
-  serialized_end=1167,
+  serialized_start=1130,
+  serialized_end=1224,
 )
 _sym_db.RegisterEnumDescriptor(_TESTENUM)
 
@@ -268,6 +268,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='remoteexec_config', full_name='chromite.api.TestRequestMessage.remoteexec_config', index=15,
+      number=16, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -281,7 +288,7 @@
   oneofs=[
   ],
   serialized_start=283,
-  serialized_end=868,
+  serialized_end=925,
 )
 
 
@@ -340,8 +347,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=871,
-  serialized_end=1071,
+  serialized_start=928,
+  serialized_end=1128,
 )
 
 _NESTEDPATH.fields_by_name['path'].message_type = chromiumos_dot_common__pb2._PATH
@@ -358,6 +365,7 @@
 _TESTREQUESTMESSAGE.fields_by_name['messages'].message_type = _MULTIFIELDMESSAGE
 _TESTREQUESTMESSAGE.fields_by_name['test_enum'].enum_type = _TESTENUM
 _TESTREQUESTMESSAGE.fields_by_name['test_enums'].enum_type = _TESTENUM
+_TESTREQUESTMESSAGE.fields_by_name['remoteexec_config'].message_type = chromiumos_dot_common__pb2._REMOTEEXECCONFIG
 _TESTRESULTMESSAGE.fields_by_name['artifact'].message_type = chromiumos_dot_common__pb2._PATH
 _TESTRESULTMESSAGE.fields_by_name['nested_artifact'].message_type = _NESTEDPATH
 _TESTRESULTMESSAGE.fields_by_name['artifacts'].message_type = chromiumos_dot_common__pb2._PATH
@@ -407,8 +415,8 @@
   index=0,
   serialized_options=b'\302\355\032\020\n\016build_api_test',
   create_key=_descriptor._internal_create_key,
-  serialized_start=1170,
-  serialized_end=1490,
+  serialized_start=1227,
+  serialized_end=1547,
   methods=[
   _descriptor.MethodDescriptor(
     name='InputOutputMethod',
@@ -453,8 +461,8 @@
   index=1,
   serialized_options=b'\302\355\032\022\n\016build_api_test\020\001',
   create_key=_descriptor._internal_create_key,
-  serialized_start=1493,
-  serialized_end=1742,
+  serialized_start=1550,
+  serialized_end=1799,
   methods=[
   _descriptor.MethodDescriptor(
     name='InsideServiceInsideMethod',
@@ -489,8 +497,8 @@
   index=2,
   serialized_options=b'\302\355\032\022\n\016build_api_test\020\002',
   create_key=_descriptor._internal_create_key,
-  serialized_start=1745,
-  serialized_end=1997,
+  serialized_start=1802,
+  serialized_end=2054,
   methods=[
   _descriptor.MethodDescriptor(
     name='OutsideServiceOutsideMethod',
@@ -525,8 +533,8 @@
   index=3,
   serialized_options=b'\302\355\032\024\n\016build_api_test\020\002\030\002',
   create_key=_descriptor._internal_create_key,
-  serialized_start=1999,
-  serialized_end=2123,
+  serialized_start=2056,
+  serialized_end=2180,
   methods=[
   _descriptor.MethodDescriptor(
     name='HiddenMethod',
diff --git a/api/gen/chromite/api/firmware_pb2.py b/api/gen/chromite/api/firmware_pb2.py
index 5773137..79ea6c3 100644
--- a/api/gen/chromite/api/firmware_pb2.py
+++ b/api/gen/chromite/api/firmware_pb2.py
@@ -21,7 +21,7 @@
   syntax='proto3',
   serialized_options=b'Z6go.chromium.org/chromiumos/infra/proto/go/chromite/api',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n\x1b\x63hromite/api/firmware.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x17\x63hromiumos/common.proto\"(\n\x0e\x42\x63sVersionInfo\x12\x16\n\x0eversion_string\x18\x01 \x01(\t\"-\n\x13\x46irmwareVersionInfo\x12\x16\n\x0eversion_string\x18\x01 \x01(\t\"\xfe\x02\n\rFwBuildMetric\x12\x13\n\x0btarget_name\x18\x01 \x01(\t\x12\x15\n\rplatform_name\x18\x02 \x01(\t\x12\x39\n\nfw_section\x18\x03 \x03(\x0b\x32%.chromite.api.FwBuildMetric.FwSection\x12:\n\x06zephyr\x18\x04 \x01(\x0b\x32(.chromite.api.FwBuildMetric.ZephyrTargetH\x00\x1a\x38\n\tFwSection\x12\x0e\n\x06region\x18\x01 \x01(\t\x12\x0c\n\x04used\x18\x02 \x01(\r\x12\r\n\x05total\x18\x03 \x01(\r\x1a\x35\n\x07Version\x12\r\n\x05major\x18\x01 \x01(\r\x12\r\n\x05minor\x18\x02 \x01(\r\x12\x0c\n\x04tiny\x18\x03 \x01(\r\x1aK\n\x0cZephyrTarget\x12;\n\x0ekernel_version\x18\x01 \x01(\x0b\x32#.chromite.api.FwBuildMetric.VersionB\x0c\n\nimage_type\"?\n\x11\x46wBuildMetricList\x12*\n\x05value\x18\x01 \x03(\x0b\x32\x1b.chromite.api.FwBuildMetric\"\x1c\n\x0c\x46wTestMetric\x12\x0c\n\x04name\x18\x01 \x01(\t\"=\n\x10\x46wTestMetricList\x12)\n\x05value\x18\x01 \x03(\x0b\x32\x1a.chromite.api.FwTestMetric\"\x87\x01\n\x17\x42uildAllFirmwareRequest\x12\x31\n\x11\x66irmware_location\x18\x01 \x01(\x0e\x32\x16.chromiumos.FwLocation\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x15\n\rcode_coverage\x18\x03 \x01(\x08\"L\n\x18\x42uildAllFirmwareResponse\x12\x30\n\x07metrics\x18\x01 \x01(\x0b\x32\x1f.chromite.api.FwBuildMetricList\"\x86\x01\n\x16TestAllFirmwareRequest\x12\x31\n\x11\x66irmware_location\x18\x01 \x01(\x0e\x32\x16.chromiumos.FwLocation\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x15\n\rcode_coverage\x18\x03 \x01(\x08\"J\n\x17TestAllFirmwareResponse\x12/\n\x07metrics\x18\x01 \x01(\x0b\x32\x1e.chromite.api.FwTestMetricList\"\xfe\x01\n\x1e\x42undleFirmwareArtifactsRequest\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12+\n\x0bresult_path\x18\x03 \x01(\x0b\x32\x16.chromiumos.ResultPath\x12:\n\tartifacts\x18\x04 \x01(\x0b\x32\'.chromiumos.ArtifactsByService.Firmware\x12\x17\n\x0b\x62\x63s_version\x18\x05 \x01(\tB\x02\x18\x01\x12\x36\n\x10\x62\x63s_version_info\x18\x06 \x01(\x0b\x32\x1c.chromite.api.BcsVersionInfo\"e\n\x1f\x42undleFirmwareArtifactsResponse\x12\x42\n\tartifacts\x18\x01 \x01(\x0b\x32/.chromiumos.UploadedArtifactsByService.Firmware\"\xf5\x06\n\x14\x46irmwareArtifactInfo\x12>\n\x07objects\x18\x01 \x03(\x0b\x32-.chromite.api.FirmwareArtifactInfo.ObjectInfo\x12\x36\n\x10\x62\x63s_version_info\x18\x02 \x01(\x0b\x32\x1c.chromite.api.BcsVersionInfo\x1a\x8a\x03\n\x0bTarballInfo\x12\x17\n\x0b\x62\x63s_version\x18\x01 \x01(\tB\x02\x18\x01\x12\x1b\n\x13\x66irmware_image_name\x18\x02 \x01(\t\x12N\n\x04type\x18\x03 \x01(\x0e\x32@.chromite.api.FirmwareArtifactInfo.TarballInfo.FirmwareType.Type\x12K\n\x07version\x18\x04 \x01(\x0b\x32\x36.chromite.api.FirmwareArtifactInfo.TarballInfo.VersionB\x02\x18\x01\x12@\n\x15\x66irmware_version_info\x18\x05 \x01(\x0b\x32!.chromite.api.FirmwareVersionInfo\x1a=\n\x0c\x46irmwareType\"-\n\x04Type\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x08\n\x04MAIN\x10\x01\x12\x06\n\x02\x45\x43\x10\x02\x12\x06\n\x02PD\x10\x03\x1a\'\n\x07Version\x12\r\n\x05major\x18\x01 \x01(\x05\x12\r\n\x05minor\x18\x02 \x01(\x05\x1a\x8c\x01\n\x0fLcovTarballInfo\x12N\n\x04type\x18\x01 \x01(\x0e\x32@.chromite.api.FirmwareArtifactInfo.LcovTarballInfo.LcovType.Type\x1a)\n\x08LcovType\"\x1d\n\x04Type\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x08\n\x04LCOV\x10\x01\x1a\xc8\x01\n\nObjectInfo\x12\x11\n\tfile_name\x18\x01 \x01(\t\x12\x46\n\x0ctarball_info\x18\x02 \x01(\x0b\x32..chromite.api.FirmwareArtifactInfo.TarballInfoH\x00\x12G\n\tlcov_info\x18\x03 \x01(\x0b\x32\x32.chromite.api.FirmwareArtifactInfo.LcovTarballInfoH\x00\x42\x16\n\x14\x66irmware_object_info2\xde\x02\n\x0f\x46irmwareService\x12\x61\n\x10\x42uildAllFirmware\x12%.chromite.api.BuildAllFirmwareRequest\x1a&.chromite.api.BuildAllFirmwareResponse\x12^\n\x0fTestAllFirmware\x12$.chromite.api.TestAllFirmwareRequest\x1a%.chromite.api.TestAllFirmwareResponse\x12v\n\x17\x42undleFirmwareArtifacts\x12,.chromite.api.BundleFirmwareArtifactsRequest\x1a-.chromite.api.BundleFirmwareArtifactsResponse\x1a\x10\xc2\xed\x1a\x0c\n\x08\x66irmware\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
+  serialized_pb=b'\n\x1b\x63hromite/api/firmware.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x17\x63hromiumos/common.proto\"(\n\x0e\x42\x63sVersionInfo\x12\x16\n\x0eversion_string\x18\x01 \x01(\t\"-\n\x13\x46irmwareVersionInfo\x12\x16\n\x0eversion_string\x18\x01 \x01(\t\"\x97\x03\n\rFwBuildMetric\x12\x13\n\x0btarget_name\x18\x01 \x01(\t\x12\x15\n\rplatform_name\x18\x02 \x01(\t\x12\x39\n\nfw_section\x18\x03 \x03(\x0b\x32%.chromite.api.FwBuildMetric.FwSection\x12:\n\x06zephyr\x18\x04 \x01(\x0b\x32(.chromite.api.FwBuildMetric.ZephyrTargetH\x00\x1aQ\n\tFwSection\x12\x0e\n\x06region\x18\x01 \x01(\t\x12\x0c\n\x04used\x18\x02 \x01(\r\x12\r\n\x05total\x18\x03 \x01(\r\x12\x17\n\x0ftrack_on_gerrit\x18\x04 \x01(\x08\x1a\x35\n\x07Version\x12\r\n\x05major\x18\x01 \x01(\r\x12\r\n\x05minor\x18\x02 \x01(\r\x12\x0c\n\x04tiny\x18\x03 \x01(\r\x1aK\n\x0cZephyrTarget\x12;\n\x0ekernel_version\x18\x01 \x01(\x0b\x32#.chromite.api.FwBuildMetric.VersionB\x0c\n\nimage_type\"?\n\x11\x46wBuildMetricList\x12*\n\x05value\x18\x01 \x03(\x0b\x32\x1b.chromite.api.FwBuildMetric\"\x1c\n\x0c\x46wTestMetric\x12\x0c\n\x04name\x18\x01 \x01(\t\"=\n\x10\x46wTestMetricList\x12)\n\x05value\x18\x01 \x03(\x0b\x32\x1a.chromite.api.FwTestMetric\"\x87\x01\n\x17\x42uildAllFirmwareRequest\x12\x31\n\x11\x66irmware_location\x18\x01 \x01(\x0e\x32\x16.chromiumos.FwLocation\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x15\n\rcode_coverage\x18\x03 \x01(\x08\"L\n\x18\x42uildAllFirmwareResponse\x12\x30\n\x07metrics\x18\x01 \x01(\x0b\x32\x1f.chromite.api.FwBuildMetricList\"\x86\x01\n\x16TestAllFirmwareRequest\x12\x31\n\x11\x66irmware_location\x18\x01 \x01(\x0e\x32\x16.chromiumos.FwLocation\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x15\n\rcode_coverage\x18\x03 \x01(\x08\"J\n\x17TestAllFirmwareResponse\x12/\n\x07metrics\x18\x01 \x01(\x0b\x32\x1e.chromite.api.FwTestMetricList\"\xfe\x01\n\x1e\x42undleFirmwareArtifactsRequest\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12+\n\x0bresult_path\x18\x03 \x01(\x0b\x32\x16.chromiumos.ResultPath\x12:\n\tartifacts\x18\x04 \x01(\x0b\x32\'.chromiumos.ArtifactsByService.Firmware\x12\x17\n\x0b\x62\x63s_version\x18\x05 \x01(\tB\x02\x18\x01\x12\x36\n\x10\x62\x63s_version_info\x18\x06 \x01(\x0b\x32\x1c.chromite.api.BcsVersionInfo\"e\n\x1f\x42undleFirmwareArtifactsResponse\x12\x42\n\tartifacts\x18\x01 \x01(\x0b\x32/.chromiumos.UploadedArtifactsByService.Firmware\"\xf5\x06\n\x14\x46irmwareArtifactInfo\x12>\n\x07objects\x18\x01 \x03(\x0b\x32-.chromite.api.FirmwareArtifactInfo.ObjectInfo\x12\x36\n\x10\x62\x63s_version_info\x18\x02 \x01(\x0b\x32\x1c.chromite.api.BcsVersionInfo\x1a\x8a\x03\n\x0bTarballInfo\x12\x17\n\x0b\x62\x63s_version\x18\x01 \x01(\tB\x02\x18\x01\x12\x1b\n\x13\x66irmware_image_name\x18\x02 \x01(\t\x12N\n\x04type\x18\x03 \x01(\x0e\x32@.chromite.api.FirmwareArtifactInfo.TarballInfo.FirmwareType.Type\x12K\n\x07version\x18\x04 \x01(\x0b\x32\x36.chromite.api.FirmwareArtifactInfo.TarballInfo.VersionB\x02\x18\x01\x12@\n\x15\x66irmware_version_info\x18\x05 \x01(\x0b\x32!.chromite.api.FirmwareVersionInfo\x1a=\n\x0c\x46irmwareType\"-\n\x04Type\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x08\n\x04MAIN\x10\x01\x12\x06\n\x02\x45\x43\x10\x02\x12\x06\n\x02PD\x10\x03\x1a\'\n\x07Version\x12\r\n\x05major\x18\x01 \x01(\x05\x12\r\n\x05minor\x18\x02 \x01(\x05\x1a\x8c\x01\n\x0fLcovTarballInfo\x12N\n\x04type\x18\x01 \x01(\x0e\x32@.chromite.api.FirmwareArtifactInfo.LcovTarballInfo.LcovType.Type\x1a)\n\x08LcovType\"\x1d\n\x04Type\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x08\n\x04LCOV\x10\x01\x1a\xc8\x01\n\nObjectInfo\x12\x11\n\tfile_name\x18\x01 \x01(\t\x12\x46\n\x0ctarball_info\x18\x02 \x01(\x0b\x32..chromite.api.FirmwareArtifactInfo.TarballInfoH\x00\x12G\n\tlcov_info\x18\x03 \x01(\x0b\x32\x32.chromite.api.FirmwareArtifactInfo.LcovTarballInfoH\x00\x42\x16\n\x14\x66irmware_object_info2\xde\x02\n\x0f\x46irmwareService\x12\x61\n\x10\x42uildAllFirmware\x12%.chromite.api.BuildAllFirmwareRequest\x1a&.chromite.api.BuildAllFirmwareResponse\x12^\n\x0fTestAllFirmware\x12$.chromite.api.TestAllFirmwareRequest\x1a%.chromite.api.TestAllFirmwareResponse\x12v\n\x17\x42undleFirmwareArtifacts\x12,.chromite.api.BundleFirmwareArtifactsRequest\x1a-.chromite.api.BundleFirmwareArtifactsResponse\x1a\x10\xc2\xed\x1a\x0c\n\x08\x66irmware\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
   ,
   dependencies=[chromite_dot_api_dot_build__api__pb2.DESCRIPTOR,chromiumos_dot_common__pb2.DESCRIPTOR,])
 
@@ -57,8 +57,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1975,
-  serialized_end=2020,
+  serialized_start=2000,
+  serialized_end=2045,
 )
 _sym_db.RegisterEnumDescriptor(_FIRMWAREARTIFACTINFO_TARBALLINFO_FIRMWARETYPE_TYPE)
 
@@ -82,8 +82,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2175,
-  serialized_end=2204,
+  serialized_start=2200,
+  serialized_end=2229,
 )
 _sym_db.RegisterEnumDescriptor(_FIRMWAREARTIFACTINFO_LCOVTARBALLINFO_LCOVTYPE_TYPE)
 
@@ -181,6 +181,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='track_on_gerrit', full_name='chromite.api.FwBuildMetric.FwSection.track_on_gerrit', index=3,
+      number=4, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -194,7 +201,7 @@
   oneofs=[
   ],
   serialized_start=370,
-  serialized_end=426,
+  serialized_end=451,
 )
 
 _FWBUILDMETRIC_VERSION = _descriptor.Descriptor(
@@ -238,8 +245,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=428,
-  serialized_end=481,
+  serialized_start=453,
+  serialized_end=506,
 )
 
 _FWBUILDMETRIC_ZEPHYRTARGET = _descriptor.Descriptor(
@@ -269,8 +276,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=483,
-  serialized_end=558,
+  serialized_start=508,
+  serialized_end=583,
 )
 
 _FWBUILDMETRIC = _descriptor.Descriptor(
@@ -327,7 +334,7 @@
     fields=[]),
   ],
   serialized_start=190,
-  serialized_end=572,
+  serialized_end=597,
 )
 
 
@@ -358,8 +365,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=574,
-  serialized_end=637,
+  serialized_start=599,
+  serialized_end=662,
 )
 
 
@@ -390,8 +397,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=639,
-  serialized_end=667,
+  serialized_start=664,
+  serialized_end=692,
 )
 
 
@@ -422,8 +429,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=669,
-  serialized_end=730,
+  serialized_start=694,
+  serialized_end=755,
 )
 
 
@@ -468,8 +475,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=733,
-  serialized_end=868,
+  serialized_start=758,
+  serialized_end=893,
 )
 
 
@@ -500,8 +507,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=870,
-  serialized_end=946,
+  serialized_start=895,
+  serialized_end=971,
 )
 
 
@@ -546,8 +553,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=949,
-  serialized_end=1083,
+  serialized_start=974,
+  serialized_end=1108,
 )
 
 
@@ -578,8 +585,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1085,
-  serialized_end=1159,
+  serialized_start=1110,
+  serialized_end=1184,
 )
 
 
@@ -638,8 +645,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1162,
-  serialized_end=1416,
+  serialized_start=1187,
+  serialized_end=1441,
 )
 
 
@@ -670,8 +677,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1418,
-  serialized_end=1519,
+  serialized_start=1443,
+  serialized_end=1544,
 )
 
 
@@ -696,8 +703,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1959,
-  serialized_end=2020,
+  serialized_start=1984,
+  serialized_end=2045,
 )
 
 _FIRMWAREARTIFACTINFO_TARBALLINFO_VERSION = _descriptor.Descriptor(
@@ -734,8 +741,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2022,
-  serialized_end=2061,
+  serialized_start=2047,
+  serialized_end=2086,
 )
 
 _FIRMWAREARTIFACTINFO_TARBALLINFO = _descriptor.Descriptor(
@@ -793,8 +800,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1667,
-  serialized_end=2061,
+  serialized_start=1692,
+  serialized_end=2086,
 )
 
 _FIRMWAREARTIFACTINFO_LCOVTARBALLINFO_LCOVTYPE = _descriptor.Descriptor(
@@ -818,8 +825,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2163,
-  serialized_end=2204,
+  serialized_start=2188,
+  serialized_end=2229,
 )
 
 _FIRMWAREARTIFACTINFO_LCOVTARBALLINFO = _descriptor.Descriptor(
@@ -849,8 +856,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2064,
-  serialized_end=2204,
+  serialized_start=2089,
+  serialized_end=2229,
 )
 
 _FIRMWAREARTIFACTINFO_OBJECTINFO = _descriptor.Descriptor(
@@ -899,8 +906,8 @@
       create_key=_descriptor._internal_create_key,
     fields=[]),
   ],
-  serialized_start=2207,
-  serialized_end=2407,
+  serialized_start=2232,
+  serialized_end=2432,
 )
 
 _FIRMWAREARTIFACTINFO = _descriptor.Descriptor(
@@ -937,8 +944,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1522,
-  serialized_end=2407,
+  serialized_start=1547,
+  serialized_end=2432,
 )
 
 _FWBUILDMETRIC_FWSECTION.containing_type = _FWBUILDMETRIC
@@ -1176,8 +1183,8 @@
   index=0,
   serialized_options=b'\302\355\032\014\n\010firmware\020\001',
   create_key=_descriptor._internal_create_key,
-  serialized_start=2410,
-  serialized_end=2760,
+  serialized_start=2435,
+  serialized_end=2785,
   methods=[
   _descriptor.MethodDescriptor(
     name='BuildAllFirmware',
diff --git a/api/gen/chromite/api/image_pb2.py b/api/gen/chromite/api/image_pb2.py
index 1c10411..5311ced 100644
--- a/api/gen/chromite/api/image_pb2.py
+++ b/api/gen/chromite/api/image_pb2.py
@@ -23,7 +23,7 @@
   syntax='proto3',
   serialized_options=b'Z6go.chromium.org/chromiumos/infra/proto/go/chromite/api',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n\x18\x63hromite/api/image.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x1a\x63hromite/api/sysroot.proto\x1a\x17\x63hromiumos/common.proto\x1a\x18\x63hromiumos/metrics.proto\"i\n\x05Image\x12\x0c\n\x04path\x18\x01 \x01(\t\x12#\n\x04type\x18\x02 \x01(\x0e\x32\x15.chromiumos.ImageType\x12-\n\x0c\x62uild_target\x18\x03 \x01(\x0b\x32\x17.chromiumos.BuildTarget\"\xf4\x01\n\x12\x43reateImageRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12*\n\x0bimage_types\x18\x02 \x03(\x0e\x32\x15.chromiumos.ImageType\x12#\n\x1b\x64isable_rootfs_verification\x18\x03 \x01(\x08\x12\x0f\n\x07version\x18\x04 \x01(\t\x12\x13\n\x0b\x64isk_layout\x18\x05 \x01(\t\x12\x14\n\x0c\x62uilder_path\x18\x06 \x01(\t\x12\"\n\x06\x63hroot\x18\x07 \x01(\x0b\x32\x12.chromiumos.Chroot\"\xa4\x01\n\x11\x43reateImageResult\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12#\n\x06images\x18\x02 \x03(\x0b\x32\x13.chromite.api.Image\x12\x30\n\x0f\x66\x61iled_packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\'\n\x06\x65vents\x18\x04 \x03(\x0b\x32\x17.chromiumos.MetricEvent\"\xdd\x01\n\x10TestImageRequest\x12\"\n\x05image\x18\x01 \x01(\x0b\x32\x13.chromite.api.Image\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x35\n\x06result\x18\x03 \x01(\x0b\x32%.chromite.api.TestImageRequest.Result\x12\"\n\x06\x63hroot\x18\x04 \x01(\x0b\x32\x12.chromiumos.Chroot\x1a\x1b\n\x06Result\x12\x11\n\tdirectory\x18\x01 \x01(\t\"\"\n\x0fTestImageResult\x12\x0f\n\x07success\x18\x01 \x01(\x08\"\xa5\x02\n\x10PushImageRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x0e\n\x06\x64ryrun\x18\x02 \x01(\x08\x12\x14\n\x0cgs_image_dir\x18\x03 \x01(\t\x12&\n\x07sysroot\x18\x04 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12$\n\x07profile\x18\x05 \x01(\x0b\x32\x13.chromiumos.Profile\x12)\n\nsign_types\x18\x06 \x03(\x0e\x32\x15.chromiumos.ImageType\x12\x13\n\x0b\x64\x65st_bucket\x18\x07 \x01(\t\x12\x12\n\nis_staging\x18\x08 \x01(\x08\x12%\n\x08\x63hannels\x18\t \x03(\x0e\x32\x13.chromiumos.Channel\"\x13\n\x11PushImageResponse2\xcc\x02\n\x0cImageService\x12K\n\x06\x43reate\x12 .chromite.api.CreateImageRequest\x1a\x1f.chromite.api.CreateImageResult\x12\x45\n\x04Test\x12\x1e.chromite.api.TestImageRequest\x1a\x1d.chromite.api.TestImageResult\x12K\n\nSignerTest\x12\x1e.chromite.api.TestImageRequest\x1a\x1d.chromite.api.TestImageResult\x12L\n\tPushImage\x12\x1e.chromite.api.PushImageRequest\x1a\x1f.chromite.api.PushImageResponse\x1a\r\xc2\xed\x1a\t\n\x05image\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
+  serialized_pb=b'\n\x18\x63hromite/api/image.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x1a\x63hromite/api/sysroot.proto\x1a\x17\x63hromiumos/common.proto\x1a\x18\x63hromiumos/metrics.proto\"i\n\x05Image\x12\x0c\n\x04path\x18\x01 \x01(\t\x12#\n\x04type\x18\x02 \x01(\x0e\x32\x15.chromiumos.ImageType\x12-\n\x0c\x62uild_target\x18\x03 \x01(\x0b\x32\x17.chromiumos.BuildTarget\"\xf4\x01\n\x12\x43reateImageRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12*\n\x0bimage_types\x18\x02 \x03(\x0e\x32\x15.chromiumos.ImageType\x12#\n\x1b\x64isable_rootfs_verification\x18\x03 \x01(\x08\x12\x0f\n\x07version\x18\x04 \x01(\t\x12\x13\n\x0b\x64isk_layout\x18\x05 \x01(\t\x12\x14\n\x0c\x62uilder_path\x18\x06 \x01(\t\x12\"\n\x06\x63hroot\x18\x07 \x01(\x0b\x32\x12.chromiumos.Chroot\"\xa4\x01\n\x11\x43reateImageResult\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12#\n\x06images\x18\x02 \x03(\x0b\x32\x13.chromite.api.Image\x12\x30\n\x0f\x66\x61iled_packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\'\n\x06\x65vents\x18\x04 \x03(\x0b\x32\x17.chromiumos.MetricEvent\"\xdd\x01\n\x10TestImageRequest\x12\"\n\x05image\x18\x01 \x01(\x0b\x32\x13.chromite.api.Image\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x35\n\x06result\x18\x03 \x01(\x0b\x32%.chromite.api.TestImageRequest.Result\x12\"\n\x06\x63hroot\x18\x04 \x01(\x0b\x32\x12.chromiumos.Chroot\x1a\x1b\n\x06Result\x12\x11\n\tdirectory\x18\x01 \x01(\t\"\"\n\x0fTestImageResult\x12\x0f\n\x07success\x18\x01 \x01(\x08\"\xa5\x02\n\x10PushImageRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x0e\n\x06\x64ryrun\x18\x02 \x01(\x08\x12\x14\n\x0cgs_image_dir\x18\x03 \x01(\t\x12&\n\x07sysroot\x18\x04 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12$\n\x07profile\x18\x05 \x01(\x0b\x32\x13.chromiumos.Profile\x12)\n\nsign_types\x18\x06 \x03(\x0e\x32\x15.chromiumos.ImageType\x12\x13\n\x0b\x64\x65st_bucket\x18\x07 \x01(\t\x12\x12\n\nis_staging\x18\x08 \x01(\x08\x12%\n\x08\x63hannels\x18\t \x03(\x0e\x32\x13.chromiumos.Channel\"\x87\x01\n\x11PushImageResponse\x12\x42\n\x0cinstructions\x18\x01 \x03(\x0b\x32,.chromite.api.PushImageResponse.Instructions\x1a.\n\x0cInstructions\x12\x1e\n\x16instructions_file_path\x18\x01 \x01(\t2\xcc\x02\n\x0cImageService\x12K\n\x06\x43reate\x12 .chromite.api.CreateImageRequest\x1a\x1f.chromite.api.CreateImageResult\x12\x45\n\x04Test\x12\x1e.chromite.api.TestImageRequest\x1a\x1d.chromite.api.TestImageResult\x12K\n\nSignerTest\x12\x1e.chromite.api.TestImageRequest\x1a\x1d.chromite.api.TestImageResult\x12L\n\tPushImage\x12\x1e.chromite.api.PushImageRequest\x1a\x1f.chromite.api.PushImageResponse\x1a\r\xc2\xed\x1a\t\n\x05image\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
   ,
   dependencies=[chromite_dot_api_dot_build__api__pb2.DESCRIPTOR,chromite_dot_api_dot_sysroot__pb2.DESCRIPTOR,chromiumos_dot_common__pb2.DESCRIPTOR,chromiumos_dot_metrics__pb2.DESCRIPTOR,])
 
@@ -407,14 +407,21 @@
 )
 
 
-_PUSHIMAGERESPONSE = _descriptor.Descriptor(
-  name='PushImageResponse',
-  full_name='chromite.api.PushImageResponse',
+_PUSHIMAGERESPONSE_INSTRUCTIONS = _descriptor.Descriptor(
+  name='Instructions',
+  full_name='chromite.api.PushImageResponse.Instructions',
   filename=None,
   file=DESCRIPTOR,
   containing_type=None,
   create_key=_descriptor._internal_create_key,
   fields=[
+    _descriptor.FieldDescriptor(
+      name='instructions_file_path', full_name='chromite.api.PushImageResponse.Instructions.instructions_file_path', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -427,8 +434,39 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1228,
-  serialized_end=1247,
+  serialized_start=1318,
+  serialized_end=1364,
+)
+
+_PUSHIMAGERESPONSE = _descriptor.Descriptor(
+  name='PushImageResponse',
+  full_name='chromite.api.PushImageResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='instructions', full_name='chromite.api.PushImageResponse.instructions', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[_PUSHIMAGERESPONSE_INSTRUCTIONS, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1229,
+  serialized_end=1364,
 )
 
 _IMAGE.fields_by_name['type'].enum_type = chromiumos_dot_common__pb2._IMAGETYPE
@@ -449,6 +487,8 @@
 _PUSHIMAGEREQUEST.fields_by_name['profile'].message_type = chromiumos_dot_common__pb2._PROFILE
 _PUSHIMAGEREQUEST.fields_by_name['sign_types'].enum_type = chromiumos_dot_common__pb2._IMAGETYPE
 _PUSHIMAGEREQUEST.fields_by_name['channels'].enum_type = chromiumos_dot_common__pb2._CHANNEL
+_PUSHIMAGERESPONSE_INSTRUCTIONS.containing_type = _PUSHIMAGERESPONSE
+_PUSHIMAGERESPONSE.fields_by_name['instructions'].message_type = _PUSHIMAGERESPONSE_INSTRUCTIONS
 DESCRIPTOR.message_types_by_name['Image'] = _IMAGE
 DESCRIPTOR.message_types_by_name['CreateImageRequest'] = _CREATEIMAGEREQUEST
 DESCRIPTOR.message_types_by_name['CreateImageResult'] = _CREATEIMAGERESULT
@@ -509,11 +549,19 @@
 _sym_db.RegisterMessage(PushImageRequest)
 
 PushImageResponse = _reflection.GeneratedProtocolMessageType('PushImageResponse', (_message.Message,), {
+
+  'Instructions' : _reflection.GeneratedProtocolMessageType('Instructions', (_message.Message,), {
+    'DESCRIPTOR' : _PUSHIMAGERESPONSE_INSTRUCTIONS,
+    '__module__' : 'chromite.api.image_pb2'
+    # @@protoc_insertion_point(class_scope:chromite.api.PushImageResponse.Instructions)
+    })
+  ,
   'DESCRIPTOR' : _PUSHIMAGERESPONSE,
   '__module__' : 'chromite.api.image_pb2'
   # @@protoc_insertion_point(class_scope:chromite.api.PushImageResponse)
   })
 _sym_db.RegisterMessage(PushImageResponse)
+_sym_db.RegisterMessage(PushImageResponse.Instructions)
 
 
 DESCRIPTOR._options = None
@@ -525,8 +573,8 @@
   index=0,
   serialized_options=b'\302\355\032\t\n\005image\020\001',
   create_key=_descriptor._internal_create_key,
-  serialized_start=1250,
-  serialized_end=1582,
+  serialized_start=1367,
+  serialized_end=1699,
   methods=[
   _descriptor.MethodDescriptor(
     name='Create',
diff --git a/api/gen/chromite/api/metadata_pb2.py b/api/gen/chromite/api/metadata_pb2.py
new file mode 100644
index 0000000..36f7d47
--- /dev/null
+++ b/api/gen/chromite/api/metadata_pb2.py
@@ -0,0 +1,152 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: chromite/api/metadata.proto
+"""Generated protocol buffer code."""
+from chromite.third_party.google.protobuf import descriptor as _descriptor
+from chromite.third_party.google.protobuf import message as _message
+from chromite.third_party.google.protobuf import reflection as _reflection
+from chromite.third_party.google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from chromite.api.gen.chromite.api import build_api_pb2 as chromite_dot_api_dot_build__api__pb2
+from chromite.api.gen.chromite.api import sysroot_pb2 as chromite_dot_api_dot_sysroot__pb2
+from chromite.api.gen.chromiumos import common_pb2 as chromiumos_dot_common__pb2
+from chromite.api.gen.chromiumos.build.api import system_image_pb2 as chromiumos_dot_build_dot_api_dot_system__image__pb2
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='chromite/api/metadata.proto',
+  package='chromite.api',
+  syntax='proto3',
+  serialized_options=b'Z6go.chromium.org/chromiumos/infra/proto/go/chromite/api',
+  create_key=_descriptor._internal_create_key,
+  serialized_pb=b'\n\x1b\x63hromite/api/metadata.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x1a\x63hromite/api/sysroot.proto\x1a\x17\x63hromiumos/common.proto\x1a\'chromiumos/build/api/system_image.proto\"h\n\x1aSystemImageMetadataRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\"V\n\x1bSystemImageMetadataResponse\x12\x37\n\x0csystem_image\x18\x01 \x01(\x0b\x32!.chromiumos.build.api.SystemImage2\x8f\x01\n\x0fMetadataService\x12j\n\x13SystemImageMetadata\x12(.chromite.api.SystemImageMetadataRequest\x1a).chromite.api.SystemImageMetadataResponse\x1a\x10\xc2\xed\x1a\x0c\n\x08metadata\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
+  ,
+  dependencies=[chromite_dot_api_dot_build__api__pb2.DESCRIPTOR,chromite_dot_api_dot_sysroot__pb2.DESCRIPTOR,chromiumos_dot_common__pb2.DESCRIPTOR,chromiumos_dot_build_dot_api_dot_system__image__pb2.DESCRIPTOR,])
+
+
+
+
+_SYSTEMIMAGEMETADATAREQUEST = _descriptor.Descriptor(
+  name='SystemImageMetadataRequest',
+  full_name='chromite.api.SystemImageMetadataRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='chroot', full_name='chromite.api.SystemImageMetadataRequest.chroot', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='sysroot', full_name='chromite.api.SystemImageMetadataRequest.sysroot', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=169,
+  serialized_end=273,
+)
+
+
+_SYSTEMIMAGEMETADATARESPONSE = _descriptor.Descriptor(
+  name='SystemImageMetadataResponse',
+  full_name='chromite.api.SystemImageMetadataResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='system_image', full_name='chromite.api.SystemImageMetadataResponse.system_image', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=275,
+  serialized_end=361,
+)
+
+_SYSTEMIMAGEMETADATAREQUEST.fields_by_name['chroot'].message_type = chromiumos_dot_common__pb2._CHROOT
+_SYSTEMIMAGEMETADATAREQUEST.fields_by_name['sysroot'].message_type = chromite_dot_api_dot_sysroot__pb2._SYSROOT
+_SYSTEMIMAGEMETADATARESPONSE.fields_by_name['system_image'].message_type = chromiumos_dot_build_dot_api_dot_system__image__pb2._SYSTEMIMAGE
+DESCRIPTOR.message_types_by_name['SystemImageMetadataRequest'] = _SYSTEMIMAGEMETADATAREQUEST
+DESCRIPTOR.message_types_by_name['SystemImageMetadataResponse'] = _SYSTEMIMAGEMETADATARESPONSE
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+SystemImageMetadataRequest = _reflection.GeneratedProtocolMessageType('SystemImageMetadataRequest', (_message.Message,), {
+  'DESCRIPTOR' : _SYSTEMIMAGEMETADATAREQUEST,
+  '__module__' : 'chromite.api.metadata_pb2'
+  # @@protoc_insertion_point(class_scope:chromite.api.SystemImageMetadataRequest)
+  })
+_sym_db.RegisterMessage(SystemImageMetadataRequest)
+
+SystemImageMetadataResponse = _reflection.GeneratedProtocolMessageType('SystemImageMetadataResponse', (_message.Message,), {
+  'DESCRIPTOR' : _SYSTEMIMAGEMETADATARESPONSE,
+  '__module__' : 'chromite.api.metadata_pb2'
+  # @@protoc_insertion_point(class_scope:chromite.api.SystemImageMetadataResponse)
+  })
+_sym_db.RegisterMessage(SystemImageMetadataResponse)
+
+
+DESCRIPTOR._options = None
+
+_METADATASERVICE = _descriptor.ServiceDescriptor(
+  name='MetadataService',
+  full_name='chromite.api.MetadataService',
+  file=DESCRIPTOR,
+  index=0,
+  serialized_options=b'\302\355\032\014\n\010metadata\020\001',
+  create_key=_descriptor._internal_create_key,
+  serialized_start=364,
+  serialized_end=507,
+  methods=[
+  _descriptor.MethodDescriptor(
+    name='SystemImageMetadata',
+    full_name='chromite.api.MetadataService.SystemImageMetadata',
+    index=0,
+    containing_service=None,
+    input_type=_SYSTEMIMAGEMETADATAREQUEST,
+    output_type=_SYSTEMIMAGEMETADATARESPONSE,
+    serialized_options=None,
+    create_key=_descriptor._internal_create_key,
+  ),
+])
+_sym_db.RegisterServiceDescriptor(_METADATASERVICE)
+
+DESCRIPTOR.services_by_name['MetadataService'] = _METADATASERVICE
+
+# @@protoc_insertion_point(module_scope)
diff --git a/api/gen/chromite/api/packages_pb2.py b/api/gen/chromite/api/packages_pb2.py
index 691f5ab..4589a1e 100644
--- a/api/gen/chromite/api/packages_pb2.py
+++ b/api/gen/chromite/api/packages_pb2.py
@@ -23,7 +23,7 @@
   syntax='proto3',
   serialized_options=b'Z6go.chromium.org/chromiumos/infra/proto/go/chromite/api',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n\x1b\x63hromite/api/packages.proto\x12\x0c\x63hromite.api\x1a\x1a\x63hromite/api/binhost.proto\x1a\x1c\x63hromite/api/build_api.proto\x1a\x1a\x63hromite/api/sysroot.proto\x1a\x17\x63hromiumos/common.proto\"\x93\x01\n\x13\x42uildsChromeRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12)\n\x08packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\"-\n\x14\x42uildsChromeResponse\x12\x15\n\rbuilds_chrome\x18\x01 \x01(\x08\"n\n\x19GetAndroidMetadataRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\"f\n\x1aGetAndroidMetadataResponse\x12\x17\n\x0f\x61ndroid_package\x18\x01 \x01(\t\x12\x16\n\x0e\x61ndroid_branch\x18\x02 \x01(\t\x12\x17\n\x0f\x61ndroid_version\x18\x03 \x01(\t\"x\n\x15GetBestVisibleRequest\x12\x0c\n\x04\x61tom\x18\x01 \x01(\t\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x03 \x01(\x0b\x32\x17.chromiumos.BuildTarget\"G\n\x16GetBestVisibleResponse\x12-\n\x0cpackage_info\x18\x01 \x01(\x0b\x32\x17.chromiumos.PackageInfo\"l\n\x17GetChromeVersionRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\"+\n\x18GetChromeVersionResponse\x12\x0f\n\x07version\x18\x01 \x01(\t\"\x98\x01\n\x18GetTargetVersionsRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12)\n\x08packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\"\xd7\x01\n\x19GetTargetVersionsResponse\x12\x17\n\x0f\x61ndroid_version\x18\x01 \x01(\t\x12\x1e\n\x16\x61ndroid_branch_version\x18\x02 \x01(\t\x12\x1e\n\x16\x61ndroid_target_version\x18\x03 \x01(\t\x12\x16\n\x0e\x63hrome_version\x18\x04 \x01(\t\x12\x14\n\x0c\x66ull_version\x18\x05 \x01(\t\x12\x19\n\x11milestone_version\x18\x06 \x01(\t\x12\x18\n\x10platform_version\x18\x07 \x01(\t\"n\n\x19GetBuilderMetadataRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\"\x8a\x05\n\x1aGetBuilderMetadataResponse\x12[\n\x15\x62uild_target_metadata\x18\x01 \x03(\x0b\x32<.chromite.api.GetBuilderMetadataResponse.BuildTargetMetadata\x12N\n\x0emodel_metadata\x18\x02 \x03(\x0b\x32\x36.chromite.api.GetBuilderMetadataResponse.ModelMetadata\x1a\xaa\x01\n\rModelMetadata\x12\x12\n\nmodel_name\x18\x01 \x01(\t\x12\x1b\n\x13\x65\x63_firmware_version\x18\x02 \x01(\t\x12\x17\n\x0f\x66irmware_key_id\x18\x03 \x01(\t\x12&\n\x1emain_readonly_firmware_version\x18\x04 \x01(\t\x12\'\n\x1fmain_readwrite_firmware_version\x18\x05 \x01(\t\x1a\x91\x02\n\x13\x42uildTargetMetadata\x12\x14\n\x0c\x62uild_target\x18\x01 \x01(\t\x12 \n\x18\x61ndroid_container_branch\x18\x02 \x01(\t\x12 \n\x18\x61ndroid_container_target\x18\x03 \x01(\t\x12!\n\x19\x61ndroid_container_version\x18\x04 \x01(\t\x12\x13\n\x0b\x61rc_use_set\x18\x05 \x01(\x08\x12\x1b\n\x13\x65\x63_firmware_version\x18\x06 \x01(\t\x12\x14\n\x0c\x66ingerprints\x18\x07 \x03(\t\x12\x16\n\x0ekernel_version\x18\x08 \x01(\t\x12\x1d\n\x15main_firmware_version\x18\t \x01(\t\"}\n\x18HasChromePrebuiltRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x0e\n\x06\x63hrome\x18\x03 \x01(\x08\"1\n\x19HasChromePrebuiltResponse\x12\x14\n\x0chas_prebuilt\x18\x01 \x01(\x08\"}\n\x18NeedsChromeSourceRequest\x12=\n\x0finstall_request\x18\x01 \x01(\x0b\x32$.chromite.api.InstallPackagesRequest\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\"\xa9\x02\n\x19NeedsChromeSourceResponse\x12\x1b\n\x13needs_chrome_source\x18\x01 \x01(\x08\x12?\n\x07reasons\x18\x02 \x03(\x0e\x32..chromite.api.NeedsChromeSourceResponse.Reason\x12)\n\x08packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\x15\n\rbuilds_chrome\x18\x04 \x01(\x08\"l\n\x06Reason\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x0f\n\x0bNO_PREBUILT\x10\x01\x12\x12\n\x0e\x43OMPILE_SOURCE\x10\x02\x12\x0f\n\x0bLOCAL_UPREV\x10\x03\x12\x1b\n\x17\x46OLLOWER_LACKS_PREBUILT\x10\x04\"\xa6\x01\n\x12HasPrebuiltRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x0e\n\x06\x63hrome\x18\x03 \x01(\x08\x12-\n\x0cpackage_info\x18\x04 \x01(\x0b\x32\x17.chromiumos.PackageInfo\"+\n\x13HasPrebuiltResponse\x12\x14\n\x0chas_prebuilt\x18\x01 \x01(\x08\"\xaf\x01\n\x14UprevPackagesRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12.\n\rbuild_targets\x18\x02 \x03(\x0b\x32\x17.chromiumos.BuildTarget\x12/\n\x0coverlay_type\x18\x03 \x01(\x0e\x32\x19.chromite.api.OverlayType\x12\x12\n\noutput_dir\x18\x04 \x01(\t\"\xa3\x02\n\x1cUprevVersionedPackageRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0cpackage_info\x18\x02 \x01(\x0b\x32\x17.chromiumos.PackageInfo\x12\x43\n\x08versions\x18\x03 \x03(\x0b\x32\x31.chromite.api.UprevVersionedPackageRequest.GitRef\x12.\n\rbuild_targets\x18\x04 \x03(\x0b\x32\x17.chromiumos.BuildTarget\x1a;\n\x06GitRef\x12\x12\n\nrepository\x18\x01 \x01(\t\x12\x0b\n\x03ref\x18\x02 \x01(\t\x12\x10\n\x08revision\x18\x03 \x01(\t\"\xb1\x01\n\x15UprevPackagesResponse\x12\x44\n\x10modified_ebuilds\x18\x01 \x03(\x0b\x32*.chromite.api.UprevPackagesResponse.Ebuild\x12\x0f\n\x07version\x18\x02 \x01(\t\x12)\n\x08packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x1a\x16\n\x06\x45\x62uild\x12\x0c\n\x04path\x18\x01 \x01(\t\"W\n\x1dUprevVersionedPackageResponse\x12\x36\n\tresponses\x18\x01 \x03(\x0b\x32#.chromite.api.UprevPackagesResponse2\xe5\x08\n\x0ePackageService\x12U\n\x0c\x42uildsChrome\x12!.chromite.api.BuildsChromeRequest\x1a\".chromite.api.BuildsChromeResponse\x12g\n\x12GetAndroidMetadata\x12\'.chromite.api.GetAndroidMetadataRequest\x1a(.chromite.api.GetAndroidMetadataResponse\x12[\n\x0eGetBestVisible\x12#.chromite.api.GetBestVisibleRequest\x1a$.chromite.api.GetBestVisibleResponse\x12\x61\n\x10GetChromeVersion\x12%.chromite.api.GetChromeVersionRequest\x1a&.chromite.api.GetChromeVersionResponse\x12\x64\n\x11GetTargetVersions\x12&.chromite.api.GetTargetVersionsRequest\x1a\'.chromite.api.GetTargetVersionsResponse\x12g\n\x12GetBuilderMetadata\x12\'.chromite.api.GetBuilderMetadataRequest\x1a(.chromite.api.GetBuilderMetadataResponse\x12\x64\n\x11HasChromePrebuilt\x12&.chromite.api.HasChromePrebuiltRequest\x1a\'.chromite.api.HasChromePrebuiltResponse\x12R\n\x0bHasPrebuilt\x12 .chromite.api.HasPrebuiltRequest\x1a!.chromite.api.HasPrebuiltResponse\x12\x64\n\x11NeedsChromeSource\x12&.chromite.api.NeedsChromeSourceRequest\x1a\'.chromite.api.NeedsChromeSourceResponse\x12X\n\x05Uprev\x12\".chromite.api.UprevPackagesRequest\x1a#.chromite.api.UprevPackagesResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x12x\n\x15UprevVersionedPackage\x12*.chromite.api.UprevVersionedPackageRequest\x1a+.chromite.api.UprevVersionedPackageResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x1a\x10\xc2\xed\x1a\x0c\n\x08packages\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
+  serialized_pb=b'\n\x1b\x63hromite/api/packages.proto\x12\x0c\x63hromite.api\x1a\x1a\x63hromite/api/binhost.proto\x1a\x1c\x63hromite/api/build_api.proto\x1a\x1a\x63hromite/api/sysroot.proto\x1a\x17\x63hromiumos/common.proto\"\x93\x01\n\x13\x42uildsChromeRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12)\n\x08packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\"-\n\x14\x42uildsChromeResponse\x12\x15\n\rbuilds_chrome\x18\x01 \x01(\x08\"n\n\x19GetAndroidMetadataRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\"f\n\x1aGetAndroidMetadataResponse\x12\x17\n\x0f\x61ndroid_package\x18\x01 \x01(\t\x12\x16\n\x0e\x61ndroid_branch\x18\x02 \x01(\t\x12\x17\n\x0f\x61ndroid_version\x18\x03 \x01(\t\"x\n\x15GetBestVisibleRequest\x12\x0c\n\x04\x61tom\x18\x01 \x01(\t\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x03 \x01(\x0b\x32\x17.chromiumos.BuildTarget\"G\n\x16GetBestVisibleResponse\x12-\n\x0cpackage_info\x18\x01 \x01(\x0b\x32\x17.chromiumos.PackageInfo\"l\n\x17GetChromeVersionRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\"+\n\x18GetChromeVersionResponse\x12\x0f\n\x07version\x18\x01 \x01(\t\"\x98\x01\n\x18GetTargetVersionsRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12)\n\x08packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\"\xd7\x01\n\x19GetTargetVersionsResponse\x12\x17\n\x0f\x61ndroid_version\x18\x01 \x01(\t\x12\x1e\n\x16\x61ndroid_branch_version\x18\x02 \x01(\t\x12\x1e\n\x16\x61ndroid_target_version\x18\x03 \x01(\t\x12\x16\n\x0e\x63hrome_version\x18\x04 \x01(\t\x12\x14\n\x0c\x66ull_version\x18\x05 \x01(\t\x12\x19\n\x11milestone_version\x18\x06 \x01(\t\x12\x18\n\x10platform_version\x18\x07 \x01(\t\"n\n\x19GetBuilderMetadataRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\"\x8a\x05\n\x1aGetBuilderMetadataResponse\x12[\n\x15\x62uild_target_metadata\x18\x01 \x03(\x0b\x32<.chromite.api.GetBuilderMetadataResponse.BuildTargetMetadata\x12N\n\x0emodel_metadata\x18\x02 \x03(\x0b\x32\x36.chromite.api.GetBuilderMetadataResponse.ModelMetadata\x1a\xaa\x01\n\rModelMetadata\x12\x12\n\nmodel_name\x18\x01 \x01(\t\x12\x1b\n\x13\x65\x63_firmware_version\x18\x02 \x01(\t\x12\x17\n\x0f\x66irmware_key_id\x18\x03 \x01(\t\x12&\n\x1emain_readonly_firmware_version\x18\x04 \x01(\t\x12\'\n\x1fmain_readwrite_firmware_version\x18\x05 \x01(\t\x1a\x91\x02\n\x13\x42uildTargetMetadata\x12\x14\n\x0c\x62uild_target\x18\x01 \x01(\t\x12 \n\x18\x61ndroid_container_branch\x18\x02 \x01(\t\x12 \n\x18\x61ndroid_container_target\x18\x03 \x01(\t\x12!\n\x19\x61ndroid_container_version\x18\x04 \x01(\t\x12\x13\n\x0b\x61rc_use_set\x18\x05 \x01(\x08\x12\x1b\n\x13\x65\x63_firmware_version\x18\x06 \x01(\t\x12\x14\n\x0c\x66ingerprints\x18\x07 \x03(\t\x12\x16\n\x0ekernel_version\x18\x08 \x01(\t\x12\x1d\n\x15main_firmware_version\x18\t \x01(\t\"}\n\x18HasChromePrebuiltRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x0e\n\x06\x63hrome\x18\x03 \x01(\x08\"1\n\x19HasChromePrebuiltResponse\x12\x14\n\x0chas_prebuilt\x18\x01 \x01(\x08\"}\n\x18NeedsChromeSourceRequest\x12=\n\x0finstall_request\x18\x01 \x01(\x0b\x32$.chromite.api.InstallPackagesRequest\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\"\xa9\x02\n\x19NeedsChromeSourceResponse\x12\x1b\n\x13needs_chrome_source\x18\x01 \x01(\x08\x12?\n\x07reasons\x18\x02 \x03(\x0e\x32..chromite.api.NeedsChromeSourceResponse.Reason\x12)\n\x08packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\x15\n\rbuilds_chrome\x18\x04 \x01(\x08\"l\n\x06Reason\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x0f\n\x0bNO_PREBUILT\x10\x01\x12\x12\n\x0e\x43OMPILE_SOURCE\x10\x02\x12\x0f\n\x0bLOCAL_UPREV\x10\x03\x12\x1b\n\x17\x46OLLOWER_LACKS_PREBUILT\x10\x04\"\xa6\x01\n\x12HasPrebuiltRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x0e\n\x06\x63hrome\x18\x03 \x01(\x08\x12-\n\x0cpackage_info\x18\x04 \x01(\x0b\x32\x17.chromiumos.PackageInfo\"+\n\x13HasPrebuiltResponse\x12\x14\n\x0chas_prebuilt\x18\x01 \x01(\x08\"\xaf\x01\n\x14UprevPackagesRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12.\n\rbuild_targets\x18\x02 \x03(\x0b\x32\x17.chromiumos.BuildTarget\x12/\n\x0coverlay_type\x18\x03 \x01(\x0e\x32\x19.chromite.api.OverlayType\x12\x12\n\noutput_dir\x18\x04 \x01(\t\"\xa3\x02\n\x1cUprevVersionedPackageRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0cpackage_info\x18\x02 \x01(\x0b\x32\x17.chromiumos.PackageInfo\x12\x43\n\x08versions\x18\x03 \x03(\x0b\x32\x31.chromite.api.UprevVersionedPackageRequest.GitRef\x12.\n\rbuild_targets\x18\x04 \x03(\x0b\x32\x17.chromiumos.BuildTarget\x1a;\n\x06GitRef\x12\x12\n\nrepository\x18\x01 \x01(\t\x12\x0b\n\x03ref\x18\x02 \x01(\t\x12\x10\n\x08revision\x18\x03 \x01(\t\"\xd1\x01\n\x15UprevPackagesResponse\x12\x44\n\x10modified_ebuilds\x18\x01 \x03(\x0b\x32*.chromite.api.UprevPackagesResponse.Ebuild\x12\x0f\n\x07version\x18\x02 \x01(\t\x12)\n\x08packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\x1e\n\x16\x61\x64\x64itional_commit_info\x18\x04 \x01(\t\x1a\x16\n\x06\x45\x62uild\x12\x0c\n\x04path\x18\x01 \x01(\t\"W\n\x1dUprevVersionedPackageResponse\x12\x36\n\tresponses\x18\x01 \x03(\x0b\x32#.chromite.api.UprevPackagesResponse\"\x16\n\x14RevBumpChromeRequest2\xcf\t\n\x0ePackageService\x12U\n\x0c\x42uildsChrome\x12!.chromite.api.BuildsChromeRequest\x1a\".chromite.api.BuildsChromeResponse\x12g\n\x12GetAndroidMetadata\x12\'.chromite.api.GetAndroidMetadataRequest\x1a(.chromite.api.GetAndroidMetadataResponse\x12[\n\x0eGetBestVisible\x12#.chromite.api.GetBestVisibleRequest\x1a$.chromite.api.GetBestVisibleResponse\x12\x61\n\x10GetChromeVersion\x12%.chromite.api.GetChromeVersionRequest\x1a&.chromite.api.GetChromeVersionResponse\x12\x64\n\x11GetTargetVersions\x12&.chromite.api.GetTargetVersionsRequest\x1a\'.chromite.api.GetTargetVersionsResponse\x12g\n\x12GetBuilderMetadata\x12\'.chromite.api.GetBuilderMetadataRequest\x1a(.chromite.api.GetBuilderMetadataResponse\x12\x64\n\x11HasChromePrebuilt\x12&.chromite.api.HasChromePrebuiltRequest\x1a\'.chromite.api.HasChromePrebuiltResponse\x12R\n\x0bHasPrebuilt\x12 .chromite.api.HasPrebuiltRequest\x1a!.chromite.api.HasPrebuiltResponse\x12\x64\n\x11NeedsChromeSource\x12&.chromite.api.NeedsChromeSourceRequest\x1a\'.chromite.api.NeedsChromeSourceResponse\x12h\n\rRevBumpChrome\x12\".chromite.api.RevBumpChromeRequest\x1a+.chromite.api.UprevVersionedPackageResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x12X\n\x05Uprev\x12\".chromite.api.UprevPackagesRequest\x1a#.chromite.api.UprevPackagesResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x12x\n\x15UprevVersionedPackage\x12*.chromite.api.UprevVersionedPackageRequest\x1a+.chromite.api.UprevVersionedPackageResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x1a\x10\xc2\xed\x1a\x0c\n\x08packages\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
   ,
   dependencies=[chromite_dot_api_dot_binhost__pb2.DESCRIPTOR,chromite_dot_api_dot_build__api__pb2.DESCRIPTOR,chromite_dot_api_dot_sysroot__pb2.DESCRIPTOR,chromiumos_dot_common__pb2.DESCRIPTOR,])
 
@@ -1160,8 +1160,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3504,
-  serialized_end=3526,
+  serialized_start=3536,
+  serialized_end=3558,
 )
 
 _UPREVPACKAGESRESPONSE = _descriptor.Descriptor(
@@ -1193,6 +1193,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='additional_commit_info', full_name='chromite.api.UprevPackagesResponse.additional_commit_info', index=3,
+      number=4, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -1206,7 +1213,7 @@
   oneofs=[
   ],
   serialized_start=3349,
-  serialized_end=3526,
+  serialized_end=3558,
 )
 
 
@@ -1237,8 +1244,33 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3528,
-  serialized_end=3615,
+  serialized_start=3560,
+  serialized_end=3647,
+)
+
+
+_REVBUMPCHROMEREQUEST = _descriptor.Descriptor(
+  name='RevBumpChromeRequest',
+  full_name='chromite.api.RevBumpChromeRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=3649,
+  serialized_end=3671,
 )
 
 _BUILDSCHROMEREQUEST.fields_by_name['chroot'].message_type = chromiumos_dot_common__pb2._CHROOT
@@ -1304,6 +1336,7 @@
 DESCRIPTOR.message_types_by_name['UprevVersionedPackageRequest'] = _UPREVVERSIONEDPACKAGEREQUEST
 DESCRIPTOR.message_types_by_name['UprevPackagesResponse'] = _UPREVPACKAGESRESPONSE
 DESCRIPTOR.message_types_by_name['UprevVersionedPackageResponse'] = _UPREVVERSIONEDPACKAGERESPONSE
+DESCRIPTOR.message_types_by_name['RevBumpChromeRequest'] = _REVBUMPCHROMEREQUEST
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
 BuildsChromeRequest = _reflection.GeneratedProtocolMessageType('BuildsChromeRequest', (_message.Message,), {
@@ -1492,6 +1525,13 @@
   })
 _sym_db.RegisterMessage(UprevVersionedPackageResponse)
 
+RevBumpChromeRequest = _reflection.GeneratedProtocolMessageType('RevBumpChromeRequest', (_message.Message,), {
+  'DESCRIPTOR' : _REVBUMPCHROMEREQUEST,
+  '__module__' : 'chromite.api.packages_pb2'
+  # @@protoc_insertion_point(class_scope:chromite.api.RevBumpChromeRequest)
+  })
+_sym_db.RegisterMessage(RevBumpChromeRequest)
+
 
 DESCRIPTOR._options = None
 
@@ -1502,8 +1542,8 @@
   index=0,
   serialized_options=b'\302\355\032\014\n\010packages\020\001',
   create_key=_descriptor._internal_create_key,
-  serialized_start=3618,
-  serialized_end=4743,
+  serialized_start=3674,
+  serialized_end=4905,
   methods=[
   _descriptor.MethodDescriptor(
     name='BuildsChrome',
@@ -1596,9 +1636,19 @@
     create_key=_descriptor._internal_create_key,
   ),
   _descriptor.MethodDescriptor(
+    name='RevBumpChrome',
+    full_name='chromite.api.PackageService.RevBumpChrome',
+    index=9,
+    containing_service=None,
+    input_type=_REVBUMPCHROMEREQUEST,
+    output_type=_UPREVVERSIONEDPACKAGERESPONSE,
+    serialized_options=b'\302\355\032\002\020\002',
+    create_key=_descriptor._internal_create_key,
+  ),
+  _descriptor.MethodDescriptor(
     name='Uprev',
     full_name='chromite.api.PackageService.Uprev',
-    index=9,
+    index=10,
     containing_service=None,
     input_type=_UPREVPACKAGESREQUEST,
     output_type=_UPREVPACKAGESRESPONSE,
@@ -1608,7 +1658,7 @@
   _descriptor.MethodDescriptor(
     name='UprevVersionedPackage',
     full_name='chromite.api.PackageService.UprevVersionedPackage',
-    index=10,
+    index=11,
     containing_service=None,
     input_type=_UPREVVERSIONEDPACKAGEREQUEST,
     output_type=_UPREVVERSIONEDPACKAGERESPONSE,
diff --git a/api/gen/chromite/api/payload_pb2.py b/api/gen/chromite/api/payload_pb2.py
index cc9559b..213a3f9 100644
--- a/api/gen/chromite/api/payload_pb2.py
+++ b/api/gen/chromite/api/payload_pb2.py
@@ -21,12 +21,37 @@
   syntax='proto3',
   serialized_options=b'Z6go.chromium.org/chromiumos/infra/proto/go/chromite/api',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n\x1a\x63hromite/api/payload.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x17\x63hromiumos/common.proto\"h\n\x05\x42uild\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x0f\n\x07version\x18\x02 \x01(\t\x12\x0e\n\x06\x62ucket\x18\x03 \x01(\t\x12\x0f\n\x07\x63hannel\x18\x04 \x01(\t\"\x91\x01\n\x08\x44LCImage\x12\"\n\x05\x62uild\x18\x01 \x01(\x0b\x32\x13.chromite.api.Build\x12\x0e\n\x06\x64lc_id\x18\x02 \x01(\t\x12\x13\n\x0b\x64lc_package\x18\x03 \x01(\t\x12\x11\n\tdlc_image\x18\x04 \x01(\t\x12)\n\nimage_type\x18\x05 \x01(\x0e\x32\x15.chromiumos.ImageType\"i\n\x0bSignedImage\x12\"\n\x05\x62uild\x18\x01 \x01(\x0b\x32\x13.chromite.api.Build\x12)\n\nimage_type\x18\x02 \x01(\x0e\x32\x15.chromiumos.ImageType\x12\x0b\n\x03key\x18\x03 \x01(\t\"q\n\rUnsignedImage\x12\"\n\x05\x62uild\x18\x01 \x01(\x0b\x32\x13.chromite.api.Build\x12)\n\nimage_type\x18\x02 \x01(\x0e\x32\x15.chromiumos.ImageType\x12\x11\n\tmilestone\x18\x03 \x01(\t\"\xfa\x03\n\x11GenerationRequest\x12\x15\n\x0b\x66ull_update\x18\x01 \x01(\x08H\x00\x12\x35\n\x10src_signed_image\x18\x02 \x01(\x0b\x32\x19.chromite.api.SignedImageH\x00\x12\x39\n\x12src_unsigned_image\x18\x03 \x01(\x0b\x32\x1b.chromite.api.UnsignedImageH\x00\x12/\n\rsrc_dlc_image\x18\n \x01(\x0b\x32\x16.chromite.api.DLCImageH\x00\x12\x35\n\x10tgt_signed_image\x18\x04 \x01(\x0b\x32\x19.chromite.api.SignedImageH\x01\x12\x39\n\x12tgt_unsigned_image\x18\x05 \x01(\x0b\x32\x1b.chromite.api.UnsignedImageH\x01\x12/\n\rtgt_dlc_image\x18\x0b \x01(\x0b\x32\x16.chromite.api.DLCImageH\x01\x12\x0e\n\x06\x62ucket\x18\x06 \x01(\t\x12\x0e\n\x06verify\x18\x07 \x01(\x08\x12\x0e\n\x06keyset\x18\x08 \x01(\t\x12\x0e\n\x06\x64ryrun\x18\t \x01(\x08\x12\"\n\x06\x63hroot\x18\x0c \x01(\x0b\x32\x12.chromiumos.ChrootB\x11\n\x0fsrc_image_oneofB\x11\n\x0ftgt_image_oneof\"M\n\x12GenerationResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x12\n\nlocal_path\x18\x02 \x01(\t\x12\x12\n\nremote_uri\x18\x03 \x01(\t2w\n\x0ePayloadService\x12T\n\x0fGeneratePayload\x12\x1f.chromite.api.GenerationRequest\x1a .chromite.api.GenerationResponse\x1a\x0f\xc2\xed\x1a\x0b\n\x07payload\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
+  serialized_pb=b'\n\x1a\x63hromite/api/payload.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x17\x63hromiumos/common.proto\"h\n\x05\x42uild\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x0f\n\x07version\x18\x02 \x01(\t\x12\x0e\n\x06\x62ucket\x18\x03 \x01(\t\x12\x0f\n\x07\x63hannel\x18\x04 \x01(\t\"\x91\x01\n\x08\x44LCImage\x12\"\n\x05\x62uild\x18\x01 \x01(\x0b\x32\x13.chromite.api.Build\x12\x0e\n\x06\x64lc_id\x18\x02 \x01(\t\x12\x13\n\x0b\x64lc_package\x18\x03 \x01(\t\x12\x11\n\tdlc_image\x18\x04 \x01(\t\x12)\n\nimage_type\x18\x05 \x01(\x0e\x32\x15.chromiumos.ImageType\"i\n\x0bSignedImage\x12\"\n\x05\x62uild\x18\x01 \x01(\x0b\x32\x13.chromite.api.Build\x12)\n\nimage_type\x18\x02 \x01(\x0e\x32\x15.chromiumos.ImageType\x12\x0b\n\x03key\x18\x03 \x01(\t\"q\n\rUnsignedImage\x12\"\n\x05\x62uild\x18\x01 \x01(\x0b\x32\x13.chromite.api.Build\x12)\n\nimage_type\x18\x02 \x01(\x0e\x32\x15.chromiumos.ImageType\x12\x11\n\tmilestone\x18\x03 \x01(\t\"\x8a\x04\n\x11GenerationRequest\x12\x15\n\x0b\x66ull_update\x18\x01 \x01(\x08H\x00\x12\x35\n\x10src_signed_image\x18\x02 \x01(\x0b\x32\x19.chromite.api.SignedImageH\x00\x12\x39\n\x12src_unsigned_image\x18\x03 \x01(\x0b\x32\x1b.chromite.api.UnsignedImageH\x00\x12/\n\rsrc_dlc_image\x18\n \x01(\x0b\x32\x16.chromite.api.DLCImageH\x00\x12\x35\n\x10tgt_signed_image\x18\x04 \x01(\x0b\x32\x19.chromite.api.SignedImageH\x01\x12\x39\n\x12tgt_unsigned_image\x18\x05 \x01(\x0b\x32\x1b.chromite.api.UnsignedImageH\x01\x12/\n\rtgt_dlc_image\x18\x0b \x01(\x0b\x32\x16.chromite.api.DLCImageH\x01\x12\x0e\n\x06\x62ucket\x18\x06 \x01(\t\x12\x0e\n\x06verify\x18\x07 \x01(\x08\x12\x0e\n\x06keyset\x18\x08 \x01(\t\x12\x0e\n\x06\x64ryrun\x18\t \x01(\x08\x12\"\n\x06\x63hroot\x18\x0c \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x0e\n\x06minios\x18\r \x01(\x08\x42\x11\n\x0fsrc_image_oneofB\x11\n\x0ftgt_image_oneof\"\xd2\x01\n\x12GenerationResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x12\n\nlocal_path\x18\x02 \x01(\t\x12\x12\n\nremote_uri\x18\x03 \x01(\t\x12\x46\n\x0e\x66\x61ilure_reason\x18\x04 \x01(\x0e\x32..chromite.api.GenerationResponse.FailureReason\";\n\rFailureReason\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x19\n\x15NOT_MINIOS_COMPATIBLE\x10\x01\x32w\n\x0ePayloadService\x12T\n\x0fGeneratePayload\x12\x1f.chromite.api.GenerationRequest\x1a .chromite.api.GenerationResponse\x1a\x0f\xc2\xed\x1a\x0b\n\x07payload\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
   ,
   dependencies=[chromite_dot_api_dot_build__api__pb2.DESCRIPTOR,chromiumos_dot_common__pb2.DESCRIPTOR,])
 
 
 
+_GENERATIONRESPONSE_FAILUREREASON = _descriptor.EnumDescriptor(
+  name='FailureReason',
+  full_name='chromite.api.GenerationResponse.FailureReason',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='UNSPECIFIED', index=0, number=0,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='NOT_MINIOS_COMPATIBLE', index=1, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=1252,
+  serialized_end=1311,
+)
+_sym_db.RegisterEnumDescriptor(_GENERATIONRESPONSE_FAILUREREASON)
+
 
 _BUILD = _descriptor.Descriptor(
   name='Build',
@@ -325,6 +350,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='minios', full_name='chromite.api.GenerationRequest.minios', index=12,
+      number=13, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -348,7 +380,7 @@
     fields=[]),
   ],
   serialized_start=576,
-  serialized_end=1082,
+  serialized_end=1098,
 )
 
 
@@ -381,11 +413,19 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='failure_reason', full_name='chromite.api.GenerationResponse.failure_reason', index=3,
+      number=4, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
   nested_types=[],
   enum_types=[
+    _GENERATIONRESPONSE_FAILUREREASON,
   ],
   serialized_options=None,
   is_extendable=False,
@@ -393,8 +433,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1084,
-  serialized_end=1161,
+  serialized_start=1101,
+  serialized_end=1311,
 )
 
 _BUILD.fields_by_name['build_target'].message_type = chromiumos_dot_common__pb2._BUILDTARGET
@@ -432,6 +472,8 @@
 _GENERATIONREQUEST.oneofs_by_name['tgt_image_oneof'].fields.append(
   _GENERATIONREQUEST.fields_by_name['tgt_dlc_image'])
 _GENERATIONREQUEST.fields_by_name['tgt_dlc_image'].containing_oneof = _GENERATIONREQUEST.oneofs_by_name['tgt_image_oneof']
+_GENERATIONRESPONSE.fields_by_name['failure_reason'].enum_type = _GENERATIONRESPONSE_FAILUREREASON
+_GENERATIONRESPONSE_FAILUREREASON.containing_type = _GENERATIONRESPONSE
 DESCRIPTOR.message_types_by_name['Build'] = _BUILD
 DESCRIPTOR.message_types_by_name['DLCImage'] = _DLCIMAGE
 DESCRIPTOR.message_types_by_name['SignedImage'] = _SIGNEDIMAGE
@@ -492,8 +534,8 @@
   index=0,
   serialized_options=b'\302\355\032\013\n\007payload\020\001',
   create_key=_descriptor._internal_create_key,
-  serialized_start=1163,
-  serialized_end=1282,
+  serialized_start=1313,
+  serialized_end=1432,
   methods=[
   _descriptor.MethodDescriptor(
     name='GeneratePayload',
diff --git a/api/gen/chromite/api/sdk_pb2.py b/api/gen/chromite/api/sdk_pb2.py
index 2f9498a..9fcda31 100644
--- a/api/gen/chromite/api/sdk_pb2.py
+++ b/api/gen/chromite/api/sdk_pb2.py
@@ -21,7 +21,7 @@
   syntax='proto3',
   serialized_options=b'Z6go.chromium.org/chromiumos/infra/proto/go/chromite/api',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n\x16\x63hromite/api/sdk.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x17\x63hromiumos/common.proto\" \n\rChrootVersion\x12\x0f\n\x07version\x18\x01 \x01(\r\"\xab\x01\n\rCreateRequest\x12\x30\n\x05\x66lags\x18\x01 \x01(\x0b\x32!.chromite.api.CreateRequest.Flags\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x1a\x44\n\x05\x46lags\x12\x12\n\nno_replace\x18\x01 \x01(\x08\x12\x11\n\tbootstrap\x18\x02 \x01(\x08\x12\x14\n\x0cno_use_image\x18\x03 \x01(\x08\">\n\x0e\x43reateResponse\x12,\n\x07version\x18\x01 \x01(\x0b\x32\x1b.chromite.api.ChrootVersion\"3\n\rDeleteRequest\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x10\n\x0e\x44\x65leteResponse\"4\n\x0eUnmountRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x11\n\x0fUnmountResponse\"\xd3\x01\n\rUpdateRequest\x12\x30\n\x05\x66lags\x18\x01 \x01(\x0b\x32!.chromite.api.UpdateRequest.Flags\x12\x32\n\x11toolchain_targets\x18\x02 \x03(\x0b\x32\x17.chromiumos.BuildTarget\x12\"\n\x06\x63hroot\x18\x03 \x01(\x0b\x32\x12.chromiumos.Chroot\x1a\x38\n\x05\x46lags\x12\x14\n\x0c\x62uild_source\x18\x01 \x01(\x08\x12\x19\n\x11toolchain_changed\x18\x02 \x01(\x08\">\n\x0eUpdateResponse\x12,\n\x07version\x18\x01 \x01(\x0b\x32\x1b.chromite.api.ChrootVersion\"2\n\x0c\x43leanRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x0f\n\rCleanResponse\"\x1e\n\rSnapshotToken\x12\r\n\x05value\x18\x01 \x01(\t\";\n\x15\x43reateSnapshotRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\"M\n\x16\x43reateSnapshotResponse\x12\x33\n\x0esnapshot_token\x18\x01 \x01(\x0b\x32\x1b.chromite.api.SnapshotToken\"q\n\x16RestoreSnapshotRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x33\n\x0esnapshot_token\x18\x02 \x01(\x0b\x32\x1b.chromite.api.SnapshotToken\"\x19\n\x17RestoreSnapshotResponse\"4\n\x12UnmountPathRequest\x12\x1e\n\x04path\x18\x01 \x01(\x0b\x32\x10.chromiumos.Path\"\x15\n\x13UnmountPathResponse2\x8b\x05\n\nSdkService\x12\x43\n\x06\x43reate\x12\x1b.chromite.api.CreateRequest\x1a\x1c.chromite.api.CreateResponse\x12\x43\n\x06\x44\x65lete\x12\x1b.chromite.api.DeleteRequest\x1a\x1c.chromite.api.DeleteResponse\x12@\n\x05\x43lean\x12\x1a.chromite.api.CleanRequest\x1a\x1b.chromite.api.CleanResponse\x12\x46\n\x07Unmount\x12\x1c.chromite.api.UnmountRequest\x1a\x1d.chromite.api.UnmountResponse\x12K\n\x06Update\x12\x1b.chromite.api.UpdateRequest\x1a\x1c.chromite.api.UpdateResponse\"\x06\xc2\xed\x1a\x02\x10\x01\x12[\n\x0e\x43reateSnapshot\x12#.chromite.api.CreateSnapshotRequest\x1a$.chromite.api.CreateSnapshotResponse\x12^\n\x0fRestoreSnapshot\x12$.chromite.api.RestoreSnapshotRequest\x1a%.chromite.api.RestoreSnapshotResponse\x12R\n\x0bUnmountPath\x12 .chromite.api.UnmountPathRequest\x1a!.chromite.api.UnmountPathResponse\x1a\x0b\xc2\xed\x1a\x07\n\x03sdk\x10\x02\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
+  serialized_pb=b'\n\x16\x63hromite/api/sdk.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x17\x63hromiumos/common.proto\" \n\rChrootVersion\x12\x0f\n\x07version\x18\x01 \x01(\r\"\xc0\x01\n\rCreateRequest\x12\x30\n\x05\x66lags\x18\x01 \x01(\x0b\x32!.chromite.api.CreateRequest.Flags\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x13\n\x0bsdk_version\x18\x03 \x01(\t\x1a\x44\n\x05\x46lags\x12\x12\n\nno_replace\x18\x01 \x01(\x08\x12\x11\n\tbootstrap\x18\x02 \x01(\x08\x12\x14\n\x0cno_use_image\x18\x03 \x01(\x08\">\n\x0e\x43reateResponse\x12,\n\x07version\x18\x01 \x01(\x0b\x32\x1b.chromite.api.ChrootVersion\"3\n\rDeleteRequest\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x10\n\x0e\x44\x65leteResponse\"4\n\x0eUnmountRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x11\n\x0fUnmountResponse\"\xd3\x01\n\rUpdateRequest\x12\x30\n\x05\x66lags\x18\x01 \x01(\x0b\x32!.chromite.api.UpdateRequest.Flags\x12\x32\n\x11toolchain_targets\x18\x02 \x03(\x0b\x32\x17.chromiumos.BuildTarget\x12\"\n\x06\x63hroot\x18\x03 \x01(\x0b\x32\x12.chromiumos.Chroot\x1a\x38\n\x05\x46lags\x12\x14\n\x0c\x62uild_source\x18\x01 \x01(\x08\x12\x19\n\x11toolchain_changed\x18\x02 \x01(\x08\">\n\x0eUpdateResponse\x12,\n\x07version\x18\x01 \x01(\x0b\x32\x1b.chromite.api.ChrootVersion\"2\n\x0c\x43leanRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x0f\n\rCleanResponse\"\x1e\n\rSnapshotToken\x12\r\n\x05value\x18\x01 \x01(\t\";\n\x15\x43reateSnapshotRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\"M\n\x16\x43reateSnapshotResponse\x12\x33\n\x0esnapshot_token\x18\x01 \x01(\x0b\x32\x1b.chromite.api.SnapshotToken\"q\n\x16RestoreSnapshotRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x33\n\x0esnapshot_token\x18\x02 \x01(\x0b\x32\x1b.chromite.api.SnapshotToken\"\x19\n\x17RestoreSnapshotResponse\"4\n\x12UnmountPathRequest\x12\x1e\n\x04path\x18\x01 \x01(\x0b\x32\x10.chromiumos.Path\"\x15\n\x13UnmountPathResponse2\x8b\x05\n\nSdkService\x12\x43\n\x06\x43reate\x12\x1b.chromite.api.CreateRequest\x1a\x1c.chromite.api.CreateResponse\x12\x43\n\x06\x44\x65lete\x12\x1b.chromite.api.DeleteRequest\x1a\x1c.chromite.api.DeleteResponse\x12@\n\x05\x43lean\x12\x1a.chromite.api.CleanRequest\x1a\x1b.chromite.api.CleanResponse\x12\x46\n\x07Unmount\x12\x1c.chromite.api.UnmountRequest\x1a\x1d.chromite.api.UnmountResponse\x12K\n\x06Update\x12\x1b.chromite.api.UpdateRequest\x1a\x1c.chromite.api.UpdateResponse\"\x06\xc2\xed\x1a\x02\x10\x01\x12[\n\x0e\x43reateSnapshot\x12#.chromite.api.CreateSnapshotRequest\x1a$.chromite.api.CreateSnapshotResponse\x12^\n\x0fRestoreSnapshot\x12$.chromite.api.RestoreSnapshotRequest\x1a%.chromite.api.RestoreSnapshotResponse\x12R\n\x0bUnmountPath\x12 .chromite.api.UnmountPathRequest\x1a!.chromite.api.UnmountPathResponse\x1a\x0b\xc2\xed\x1a\x07\n\x03sdk\x10\x02\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
   ,
   dependencies=[chromite_dot_api_dot_build__api__pb2.DESCRIPTOR,chromiumos_dot_common__pb2.DESCRIPTOR,])
 
@@ -101,8 +101,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=233,
-  serialized_end=301,
+  serialized_start=254,
+  serialized_end=322,
 )
 
 _CREATEREQUEST = _descriptor.Descriptor(
@@ -127,6 +127,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='sdk_version', full_name='chromite.api.CreateRequest.sdk_version', index=2,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -140,7 +147,7 @@
   oneofs=[
   ],
   serialized_start=130,
-  serialized_end=301,
+  serialized_end=322,
 )
 
 
@@ -171,8 +178,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=303,
-  serialized_end=365,
+  serialized_start=324,
+  serialized_end=386,
 )
 
 
@@ -203,8 +210,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=367,
-  serialized_end=418,
+  serialized_start=388,
+  serialized_end=439,
 )
 
 
@@ -228,8 +235,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=420,
-  serialized_end=436,
+  serialized_start=441,
+  serialized_end=457,
 )
 
 
@@ -260,8 +267,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=438,
-  serialized_end=490,
+  serialized_start=459,
+  serialized_end=511,
 )
 
 
@@ -285,8 +292,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=492,
-  serialized_end=509,
+  serialized_start=513,
+  serialized_end=530,
 )
 
 
@@ -324,8 +331,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=667,
-  serialized_end=723,
+  serialized_start=688,
+  serialized_end=744,
 )
 
 _UPDATEREQUEST = _descriptor.Descriptor(
@@ -369,8 +376,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=512,
-  serialized_end=723,
+  serialized_start=533,
+  serialized_end=744,
 )
 
 
@@ -401,8 +408,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=725,
-  serialized_end=787,
+  serialized_start=746,
+  serialized_end=808,
 )
 
 
@@ -433,8 +440,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=789,
-  serialized_end=839,
+  serialized_start=810,
+  serialized_end=860,
 )
 
 
@@ -458,8 +465,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=841,
-  serialized_end=856,
+  serialized_start=862,
+  serialized_end=877,
 )
 
 
@@ -490,8 +497,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=858,
-  serialized_end=888,
+  serialized_start=879,
+  serialized_end=909,
 )
 
 
@@ -522,8 +529,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=890,
-  serialized_end=949,
+  serialized_start=911,
+  serialized_end=970,
 )
 
 
@@ -554,8 +561,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=951,
-  serialized_end=1028,
+  serialized_start=972,
+  serialized_end=1049,
 )
 
 
@@ -593,8 +600,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1030,
-  serialized_end=1143,
+  serialized_start=1051,
+  serialized_end=1164,
 )
 
 
@@ -618,8 +625,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1145,
-  serialized_end=1170,
+  serialized_start=1166,
+  serialized_end=1191,
 )
 
 
@@ -650,8 +657,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1172,
-  serialized_end=1224,
+  serialized_start=1193,
+  serialized_end=1245,
 )
 
 
@@ -675,8 +682,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1226,
-  serialized_end=1247,
+  serialized_start=1247,
+  serialized_end=1268,
 )
 
 _CREATEREQUEST_FLAGS.containing_type = _CREATEREQUEST
@@ -868,8 +875,8 @@
   index=0,
   serialized_options=b'\302\355\032\007\n\003sdk\020\002',
   create_key=_descriptor._internal_create_key,
-  serialized_start=1250,
-  serialized_end=1901,
+  serialized_start=1271,
+  serialized_end=1922,
   methods=[
   _descriptor.MethodDescriptor(
     name='Create',
diff --git a/api/gen/chromite/api/sysroot_pb2.py b/api/gen/chromite/api/sysroot_pb2.py
index 96f0038..3aa1923 100644
--- a/api/gen/chromite/api/sysroot_pb2.py
+++ b/api/gen/chromite/api/sysroot_pb2.py
@@ -22,7 +22,7 @@
   syntax='proto3',
   serialized_options=b'Z6go.chromium.org/chromiumos/infra/proto/go/chromite/api',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n\x1a\x63hromite/api/sysroot.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x17\x63hromiumos/common.proto\x1a\x18\x63hromiumos/metrics.proto\"F\n\x07Sysroot\x12\x0c\n\x04path\x18\x01 \x01(\t\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\"\x17\n\x07Profile\x12\x0c\n\x04name\x18\x01 \x01(\t\"\xce\x02\n\x14SysrootCreateRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x37\n\x05\x66lags\x18\x02 \x01(\x0b\x32(.chromite.api.SysrootCreateRequest.Flags\x12&\n\x07profile\x18\x03 \x01(\x0b\x32\x15.chromite.api.Profile\x12\"\n\x06\x63hroot\x18\x04 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x35\n\x0fpackage_indexes\x18\x05 \x03(\x0b\x32\x1c.chromiumos.PackageIndexInfo\x1aK\n\x05\x46lags\x12\x16\n\x0e\x63hroot_current\x18\x01 \x01(\x08\x12\x0f\n\x07replace\x18\x02 \x01(\x08\x12\x19\n\x11toolchain_changed\x18\x03 \x01(\x08\"?\n\x15SysrootCreateResponse\x12&\n\x07sysroot\x18\x01 \x01(\x0b\x32\x15.chromite.api.Sysroot\"\xc9\x01\n\x1dSysrootGenerateArchiveRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12)\n\x08packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12*\n\ntarget_dir\x18\x04 \x01(\x0b\x32\x16.chromiumos.ResultPath\"K\n\x1eSysrootGenerateArchiveResponse\x12)\n\x0fsysroot_archive\x18\x01 \x01(\x0b\x32\x10.chromiumos.Path\"\xdd\x01\n\x17InstallToolchainRequest\x12&\n\x07sysroot\x18\x01 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12:\n\x05\x66lags\x18\x02 \x01(\x0b\x32+.chromite.api.InstallToolchainRequest.Flags\x12\"\n\x06\x63hroot\x18\x03 \x01(\x0b\x32\x12.chromiumos.Chroot\x1a:\n\x05\x46lags\x12\x16\n\x0e\x63ompile_source\x18\x01 \x01(\x08\x12\x19\n\x11toolchain_changed\x18\x02 \x01(\x08\"L\n\x18InstallToolchainResponse\x12\x30\n\x0f\x66\x61iled_packages\x18\x01 \x03(\x0b\x32\x17.chromiumos.PackageInfo\"\xc6\x03\n\x16InstallPackagesRequest\x12&\n\x07sysroot\x18\x01 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\x39\n\x05\x66lags\x18\x02 \x01(\x0b\x32*.chromite.api.InstallPackagesRequest.Flags\x12)\n\x08packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\"\n\x06\x63hroot\x18\x04 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\tuse_flags\x18\x05 \x03(\x0b\x32\x13.chromiumos.UseFlag\x12+\n\x0bgoma_config\x18\x06 \x01(\x0b\x32\x16.chromiumos.GomaConfig\x12\x35\n\x0fpackage_indexes\x18\x07 \x03(\x0b\x32\x1c.chromiumos.PackageIndexInfo\x1an\n\x05\x46lags\x12\x16\n\x0e\x63ompile_source\x18\x01 \x01(\x08\x12\x10\n\x08use_goma\x18\x03 \x01(\x08\x12\x19\n\x11toolchain_changed\x18\x04 \x01(\x08\x12\x0e\n\x06\x64ryrun\x18\x05 \x01(\x08J\x04\x08\x02\x10\x03R\nevent_file\"\xa7\x01\n\x17InstallPackagesResponse\x12\x30\n\x0f\x66\x61iled_packages\x18\x01 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\'\n\x06\x65vents\x18\x02 \x03(\x0b\x32\x17.chromiumos.MetricEvent\x12\x31\n\x0egoma_artifacts\x18\x03 \x01(\x0b\x32\x19.chromiumos.GomaArtifacts\"\xb4\x01\n CreateSimpleChromeSysrootRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x11\n\tuse_flags\x18\x02 \x03(\t\x12*\n\ntarget_dir\x18\x03 \x01(\x0b\x32\x16.chromiumos.ResultPath\x12\"\n\x06\x63hroot\x18\x04 \x01(\x0b\x32\x12.chromiumos.Chroot\"N\n!CreateSimpleChromeSysrootResponse\x12)\n\x0fsysroot_archive\x18\x01 \x01(\x0b\x32\x10.chromiumos.Path2\xa3\x04\n\x0eSysrootService\x12Q\n\x06\x43reate\x12\".chromite.api.SysrootCreateRequest\x1a#.chromite.api.SysrootCreateResponse\x12l\n\x0fGenerateArchive\x12+.chromite.api.SysrootGenerateArchiveRequest\x1a,.chromite.api.SysrootGenerateArchiveResponse\x12\x61\n\x10InstallToolchain\x12%.chromite.api.InstallToolchainRequest\x1a&.chromite.api.InstallToolchainResponse\x12^\n\x0fInstallPackages\x12$.chromite.api.InstallPackagesRequest\x1a%.chromite.api.InstallPackagesResponse\x12|\n\x19\x43reateSimpleChromeSysroot\x12..chromite.api.CreateSimpleChromeSysrootRequest\x1a/.chromite.api.CreateSimpleChromeSysrootResponse\x1a\x0f\xc2\xed\x1a\x0b\n\x07sysroot\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
+  serialized_pb=b'\n\x1a\x63hromite/api/sysroot.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x17\x63hromiumos/common.proto\x1a\x18\x63hromiumos/metrics.proto\"F\n\x07Sysroot\x12\x0c\n\x04path\x18\x01 \x01(\t\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\"\x17\n\x07Profile\x12\x0c\n\x04name\x18\x01 \x01(\t\"\xce\x02\n\x14SysrootCreateRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x37\n\x05\x66lags\x18\x02 \x01(\x0b\x32(.chromite.api.SysrootCreateRequest.Flags\x12&\n\x07profile\x18\x03 \x01(\x0b\x32\x15.chromite.api.Profile\x12\"\n\x06\x63hroot\x18\x04 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x35\n\x0fpackage_indexes\x18\x05 \x03(\x0b\x32\x1c.chromiumos.PackageIndexInfo\x1aK\n\x05\x46lags\x12\x16\n\x0e\x63hroot_current\x18\x01 \x01(\x08\x12\x0f\n\x07replace\x18\x02 \x01(\x08\x12\x19\n\x11toolchain_changed\x18\x03 \x01(\x08\"?\n\x15SysrootCreateResponse\x12&\n\x07sysroot\x18\x01 \x01(\x0b\x32\x15.chromite.api.Sysroot\"\xc9\x01\n\x1dSysrootGenerateArchiveRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12)\n\x08packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12*\n\ntarget_dir\x18\x04 \x01(\x0b\x32\x16.chromiumos.ResultPath\"K\n\x1eSysrootGenerateArchiveResponse\x12)\n\x0fsysroot_archive\x18\x01 \x01(\x0b\x32\x10.chromiumos.Path\"\xdd\x01\n\x17InstallToolchainRequest\x12&\n\x07sysroot\x18\x01 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12:\n\x05\x66lags\x18\x02 \x01(\x0b\x32+.chromite.api.InstallToolchainRequest.Flags\x12\"\n\x06\x63hroot\x18\x03 \x01(\x0b\x32\x12.chromiumos.Chroot\x1a:\n\x05\x46lags\x12\x16\n\x0e\x63ompile_source\x18\x01 \x01(\x08\x12\x19\n\x11toolchain_changed\x18\x02 \x01(\x08\"\x8a\x01\n\x18InstallToolchainResponse\x12\x30\n\x0f\x66\x61iled_packages\x18\x01 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12<\n\x13\x66\x61iled_package_data\x18\x04 \x03(\x0b\x32\x1f.chromite.api.FailedPackageData\"\x96\x04\n\x16InstallPackagesRequest\x12&\n\x07sysroot\x18\x01 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\x39\n\x05\x66lags\x18\x02 \x01(\x0b\x32*.chromite.api.InstallPackagesRequest.Flags\x12)\n\x08packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\"\n\x06\x63hroot\x18\x04 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\tuse_flags\x18\x05 \x03(\x0b\x32\x13.chromiumos.UseFlag\x12+\n\x0bgoma_config\x18\x06 \x01(\x0b\x32\x16.chromiumos.GomaConfig\x12\x35\n\x0fpackage_indexes\x18\x07 \x03(\x0b\x32\x1c.chromiumos.PackageIndexInfo\x12\x37\n\x11remoteexec_config\x18\x08 \x01(\x0b\x32\x1c.chromiumos.RemoteexecConfig\x1a\x84\x01\n\x05\x46lags\x12\x16\n\x0e\x63ompile_source\x18\x01 \x01(\x08\x12\x10\n\x08use_goma\x18\x03 \x01(\x08\x12\x19\n\x11toolchain_changed\x18\x04 \x01(\x08\x12\x0e\n\x06\x64ryrun\x18\x05 \x01(\x08J\x04\x08\x02\x10\x03J\x04\x08\x06\x10\x07R\nevent_fileR\x0euse_remoteexec\"\xe5\x01\n\x17InstallPackagesResponse\x12\x30\n\x0f\x66\x61iled_packages\x18\x01 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\'\n\x06\x65vents\x18\x02 \x03(\x0b\x32\x17.chromiumos.MetricEvent\x12\x31\n\x0egoma_artifacts\x18\x03 \x01(\x0b\x32\x19.chromiumos.GomaArtifacts\x12<\n\x13\x66\x61iled_package_data\x18\x04 \x03(\x0b\x32\x1f.chromite.api.FailedPackageData\"^\n\x11\x46\x61iledPackageData\x12%\n\x04name\x18\x01 \x01(\x0b\x32\x17.chromiumos.PackageInfo\x12\"\n\x08log_path\x18\x02 \x01(\x0b\x32\x10.chromiumos.Path\"\xb4\x01\n CreateSimpleChromeSysrootRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x11\n\tuse_flags\x18\x02 \x03(\t\x12*\n\ntarget_dir\x18\x03 \x01(\x0b\x32\x16.chromiumos.ResultPath\x12\"\n\x06\x63hroot\x18\x04 \x01(\x0b\x32\x12.chromiumos.Chroot\"N\n!CreateSimpleChromeSysrootResponse\x12)\n\x0fsysroot_archive\x18\x01 \x01(\x0b\x32\x10.chromiumos.Path2\xa3\x04\n\x0eSysrootService\x12Q\n\x06\x43reate\x12\".chromite.api.SysrootCreateRequest\x1a#.chromite.api.SysrootCreateResponse\x12l\n\x0fGenerateArchive\x12+.chromite.api.SysrootGenerateArchiveRequest\x1a,.chromite.api.SysrootGenerateArchiveResponse\x12\x61\n\x10InstallToolchain\x12%.chromite.api.InstallToolchainRequest\x1a&.chromite.api.InstallToolchainResponse\x12^\n\x0fInstallPackages\x12$.chromite.api.InstallPackagesRequest\x1a%.chromite.api.InstallPackagesResponse\x12|\n\x19\x43reateSimpleChromeSysroot\x12..chromite.api.CreateSimpleChromeSysrootRequest\x1a/.chromite.api.CreateSimpleChromeSysrootResponse\x1a\x0f\xc2\xed\x1a\x0b\n\x07sysroot\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
   ,
   dependencies=[chromite_dot_api_dot_build__api__pb2.DESCRIPTOR,chromiumos_dot_common__pb2.DESCRIPTOR,chromiumos_dot_metrics__pb2.DESCRIPTOR,])
 
@@ -421,6 +421,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='failed_package_data', full_name='chromite.api.InstallToolchainResponse.failed_package_data', index=1,
+      number=4, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -433,8 +440,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1129,
-  serialized_end=1205,
+  serialized_start=1130,
+  serialized_end=1268,
 )
 
 
@@ -486,8 +493,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1552,
-  serialized_end=1662,
+  serialized_start=1673,
+  serialized_end=1805,
 )
 
 _INSTALLPACKAGESREQUEST = _descriptor.Descriptor(
@@ -547,6 +554,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='remoteexec_config', full_name='chromite.api.InstallPackagesRequest.remoteexec_config', index=7,
+      number=8, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -559,8 +573,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1208,
-  serialized_end=1662,
+  serialized_start=1271,
+  serialized_end=1805,
 )
 
 
@@ -593,6 +607,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='failed_package_data', full_name='chromite.api.InstallPackagesResponse.failed_package_data', index=3,
+      number=4, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -605,8 +626,47 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1665,
-  serialized_end=1832,
+  serialized_start=1808,
+  serialized_end=2037,
+)
+
+
+_FAILEDPACKAGEDATA = _descriptor.Descriptor(
+  name='FailedPackageData',
+  full_name='chromite.api.FailedPackageData',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='name', full_name='chromite.api.FailedPackageData.name', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='log_path', full_name='chromite.api.FailedPackageData.log_path', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2039,
+  serialized_end=2133,
 )
 
 
@@ -658,8 +718,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1835,
-  serialized_end=2015,
+  serialized_start=2136,
+  serialized_end=2316,
 )
 
 
@@ -690,8 +750,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2017,
-  serialized_end=2095,
+  serialized_start=2318,
+  serialized_end=2396,
 )
 
 _SYSROOT.fields_by_name['build_target'].message_type = chromiumos_dot_common__pb2._BUILDTARGET
@@ -712,6 +772,7 @@
 _INSTALLTOOLCHAINREQUEST.fields_by_name['flags'].message_type = _INSTALLTOOLCHAINREQUEST_FLAGS
 _INSTALLTOOLCHAINREQUEST.fields_by_name['chroot'].message_type = chromiumos_dot_common__pb2._CHROOT
 _INSTALLTOOLCHAINRESPONSE.fields_by_name['failed_packages'].message_type = chromiumos_dot_common__pb2._PACKAGEINFO
+_INSTALLTOOLCHAINRESPONSE.fields_by_name['failed_package_data'].message_type = _FAILEDPACKAGEDATA
 _INSTALLPACKAGESREQUEST_FLAGS.containing_type = _INSTALLPACKAGESREQUEST
 _INSTALLPACKAGESREQUEST.fields_by_name['sysroot'].message_type = _SYSROOT
 _INSTALLPACKAGESREQUEST.fields_by_name['flags'].message_type = _INSTALLPACKAGESREQUEST_FLAGS
@@ -720,9 +781,13 @@
 _INSTALLPACKAGESREQUEST.fields_by_name['use_flags'].message_type = chromiumos_dot_common__pb2._USEFLAG
 _INSTALLPACKAGESREQUEST.fields_by_name['goma_config'].message_type = chromiumos_dot_common__pb2._GOMACONFIG
 _INSTALLPACKAGESREQUEST.fields_by_name['package_indexes'].message_type = chromiumos_dot_common__pb2._PACKAGEINDEXINFO
+_INSTALLPACKAGESREQUEST.fields_by_name['remoteexec_config'].message_type = chromiumos_dot_common__pb2._REMOTEEXECCONFIG
 _INSTALLPACKAGESRESPONSE.fields_by_name['failed_packages'].message_type = chromiumos_dot_common__pb2._PACKAGEINFO
 _INSTALLPACKAGESRESPONSE.fields_by_name['events'].message_type = chromiumos_dot_metrics__pb2._METRICEVENT
 _INSTALLPACKAGESRESPONSE.fields_by_name['goma_artifacts'].message_type = chromiumos_dot_common__pb2._GOMAARTIFACTS
+_INSTALLPACKAGESRESPONSE.fields_by_name['failed_package_data'].message_type = _FAILEDPACKAGEDATA
+_FAILEDPACKAGEDATA.fields_by_name['name'].message_type = chromiumos_dot_common__pb2._PACKAGEINFO
+_FAILEDPACKAGEDATA.fields_by_name['log_path'].message_type = chromiumos_dot_common__pb2._PATH
 _CREATESIMPLECHROMESYSROOTREQUEST.fields_by_name['build_target'].message_type = chromiumos_dot_common__pb2._BUILDTARGET
 _CREATESIMPLECHROMESYSROOTREQUEST.fields_by_name['target_dir'].message_type = chromiumos_dot_common__pb2._RESULTPATH
 _CREATESIMPLECHROMESYSROOTREQUEST.fields_by_name['chroot'].message_type = chromiumos_dot_common__pb2._CHROOT
@@ -737,6 +802,7 @@
 DESCRIPTOR.message_types_by_name['InstallToolchainResponse'] = _INSTALLTOOLCHAINRESPONSE
 DESCRIPTOR.message_types_by_name['InstallPackagesRequest'] = _INSTALLPACKAGESREQUEST
 DESCRIPTOR.message_types_by_name['InstallPackagesResponse'] = _INSTALLPACKAGESRESPONSE
+DESCRIPTOR.message_types_by_name['FailedPackageData'] = _FAILEDPACKAGEDATA
 DESCRIPTOR.message_types_by_name['CreateSimpleChromeSysrootRequest'] = _CREATESIMPLECHROMESYSROOTREQUEST
 DESCRIPTOR.message_types_by_name['CreateSimpleChromeSysrootResponse'] = _CREATESIMPLECHROMESYSROOTRESPONSE
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
@@ -835,6 +901,13 @@
   })
 _sym_db.RegisterMessage(InstallPackagesResponse)
 
+FailedPackageData = _reflection.GeneratedProtocolMessageType('FailedPackageData', (_message.Message,), {
+  'DESCRIPTOR' : _FAILEDPACKAGEDATA,
+  '__module__' : 'chromite.api.sysroot_pb2'
+  # @@protoc_insertion_point(class_scope:chromite.api.FailedPackageData)
+  })
+_sym_db.RegisterMessage(FailedPackageData)
+
 CreateSimpleChromeSysrootRequest = _reflection.GeneratedProtocolMessageType('CreateSimpleChromeSysrootRequest', (_message.Message,), {
   'DESCRIPTOR' : _CREATESIMPLECHROMESYSROOTREQUEST,
   '__module__' : 'chromite.api.sysroot_pb2'
@@ -859,8 +932,8 @@
   index=0,
   serialized_options=b'\302\355\032\013\n\007sysroot\020\001',
   create_key=_descriptor._internal_create_key,
-  serialized_start=2098,
-  serialized_end=2645,
+  serialized_start=2399,
+  serialized_end=2946,
   methods=[
   _descriptor.MethodDescriptor(
     name='Create',
diff --git a/api/gen/chromite/api/test_pb2.py b/api/gen/chromite/api/test_pb2.py
index d4a9bfc..284651e 100644
--- a/api/gen/chromite/api/test_pb2.py
+++ b/api/gen/chromite/api/test_pb2.py
@@ -15,9 +15,7 @@
 from chromite.api.gen.chromite.api import sysroot_pb2 as chromite_dot_api_dot_sysroot__pb2
 from chromite.api.gen.chromiumos import common_pb2 as chromiumos_dot_common__pb2
 from chromite.api.gen.chromiumos import metrics_pb2 as chromiumos_dot_metrics__pb2
-from chromite.api.gen.chromiumos.test.api import coverage_rule_pb2 as chromiumos_dot_test_dot_api_dot_coverage__rule__pb2
 from chromite.api.gen.chromiumos.build.api import container_metadata_pb2 as chromiumos_dot_build_dot_api_dot_container__metadata__pb2
-from chromite.api.gen.chromiumos.test.plan import source_test_plan_pb2 as chromiumos_dot_test_dot_plan_dot_source__test__plan__pb2
 
 
 DESCRIPTOR = _descriptor.FileDescriptor(
@@ -26,9 +24,9 @@
   syntax='proto3',
   serialized_options=b'Z6go.chromium.org/chromiumos/infra/proto/go/chromite/api',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n\x17\x63hromite/api/test.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x1a\x63hromite/api/sysroot.proto\x1a\x17\x63hromiumos/common.proto\x1a\x18\x63hromiumos/metrics.proto\x1a\'chromiumos/test/api/coverage_rule.proto\x1a-chromiumos/build/api/container_metadata.proto\x1a+chromiumos/test/plan/source_test_plan.proto\"\xcf\x02\n\x1fTestServiceContainerBuildResult\x12\x0c\n\x04name\x18\x01 \x01(\t\x12H\n\x07success\x18\x02 \x01(\x0b\x32\x35.chromite.api.TestServiceContainerBuildResult.SuccessH\x00\x12H\n\x07\x66\x61ilure\x18\x03 \x01(\x0b\x32\x35.chromite.api.TestServiceContainerBuildResult.FailureH\x00\x1a^\n\x07Success\x12<\n\nimage_info\x18\x02 \x01(\x0b\x32(.chromiumos.build.api.ContainerImageInfo\x12\x15\n\rregistry_path\x18\x01 \x01(\t\x1a \n\x07\x46\x61ilure\x12\x15\n\rerror_message\x18\x01 \x01(\tB\x08\n\x06result\"\xca\x02\n!BuildTestServiceContainersRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x0f\n\x07version\x18\x03 \x01(\t\x12\x37\n\nrepository\x18\x04 \x01(\x0b\x32#.chromiumos.build.api.GcrRepository\x12\x0c\n\x04tags\x18\x05 \x03(\t\x12K\n\x06labels\x18\x06 \x03(\x0b\x32;.chromite.api.BuildTestServiceContainersRequest.LabelsEntry\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"d\n\"BuildTestServiceContainersResponse\x12>\n\x07results\x18\x01 \x03(\x0b\x32-.chromite.api.TestServiceContainerBuildResult\"\xc0\x03\n\x1a\x42uildTargetUnitTestRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x13\n\x0bresult_path\x18\x02 \x01(\t\x12\"\n\x06\x63hroot\x18\x03 \x01(\x0b\x32\x12.chromiumos.Chroot\x12=\n\x05\x66lags\x18\x04 \x01(\x0b\x32..chromite.api.BuildTargetUnitTestRequest.Flags\x12)\n\x08packages\x18\x06 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\x32\n\x11package_blocklist\x18\x07 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x1a\x95\x01\n\x05\x46lags\x12\x15\n\rempty_sysroot\x18\x01 \x01(\x08\x12\x19\n\x11toolchain_changed\x18\x02 \x01(\x08\x12\x15\n\rcode_coverage\x18\x03 \x01(\x08\x12\"\n\x1atestable_packages_optional\x18\x04 \x01(\x08\x12\x1f\n\x17\x66ilter_only_cros_workon\x18\x05 \x01(\x08J\x04\x08\x05\x10\x06\"\x8e\x01\n\x1b\x42uildTargetUnitTestResponse\x12\x14\n\x0ctarball_path\x18\x01 \x01(\t\x12\x30\n\x0f\x66\x61iled_packages\x18\x02 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\'\n\x06\x65vents\x18\x03 \x03(\x0b\x32\x17.chromiumos.MetricEvent\"=\n\x17\x43hromiteUnitTestRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x1a\n\x18\x43hromiteUnitTestResponse\";\n\x15\x43hromitePytestRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x18\n\x16\x43hromitePytestResponse\"<\n\x16\x43rosSigningTestRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x19\n\x17\x43rosSigningTestResponse\"b\n\x14\x44\x65\x62ugInfoTestRequest\x12&\n\x07sysroot\x18\x01 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x17\n\x15\x44\x65\x62ugInfoTestResponse\"\xd2\x03\n\rVmTestRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12!\n\x07vm_path\x18\x03 \x01(\x0b\x32\x10.chromiumos.Path\x12;\n\x0bssh_options\x18\x04 \x01(\x0b\x32&.chromite.api.VmTestRequest.SshOptions\x12=\n\x0ctest_harness\x18\x05 \x01(\x0e\x32\'.chromite.api.VmTestRequest.TestHarness\x12\x34\n\x08vm_tests\x18\x06 \x03(\x0b\x32\".chromite.api.VmTestRequest.VmTest\x1a\x46\n\nSshOptions\x12*\n\x10private_key_path\x18\x01 \x01(\x0b\x32\x10.chromiumos.Path\x12\x0c\n\x04port\x18\x02 \x01(\x05\x1a\x19\n\x06VmTest\x12\x0f\n\x07pattern\x18\x01 \x01(\t\"6\n\x0bTestHarness\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x08\n\x04TAST\x10\x01\x12\x0c\n\x08\x41UTOTEST\x10\x02\"\x10\n\x0eVmTestResponse\"\xe9\x01\n\x13MoblabVmTestRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12@\n\rimage_payload\x18\x02 \x01(\x0b\x32).chromite.api.MoblabVmTestRequest.Payload\x12\x41\n\x0e\x63\x61\x63he_payloads\x18\x03 \x03(\x0b\x32).chromite.api.MoblabVmTestRequest.Payload\x1a)\n\x07Payload\x12\x1e\n\x04path\x18\x01 \x01(\x0b\x32\x10.chromiumos.Path\"\x16\n\x14MoblabVmTestResponse\"\x8b\x01\n\x1fSimpleChromeWorkflowTestRequest\x12&\n\x07sysroot\x18\x01 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\x13\n\x0b\x63hrome_root\x18\x02 \x01(\t\x12+\n\x0bgoma_config\x18\x03 \x01(\x0b\x32\x16.chromiumos.GomaConfig\"\"\n SimpleChromeWorkflowTestResponse\"\x87\x02\n\x17GetCoverageRulesRequest\x12\"\n\x06\x63hroot\x18\x05 \x01(\x0b\x32\x12.chromiumos.Chroot\x12?\n\x11source_test_plans\x18\x01 \x03(\x0b\x32$.chromiumos.test.plan.SourceTestPlan\x12-\n\x13\x62uild_metadata_list\x18\x02 \x01(\x0b\x32\x10.chromiumos.Path\x12,\n\x12\x64ut_attribute_list\x18\x03 \x01(\x0b\x32\x10.chromiumos.Path\x12*\n\x10\x66lat_config_list\x18\x04 \x01(\x0b\x32\x10.chromiumos.Path\"U\n\x18GetCoverageRulesResponse\x12\x39\n\x0e\x63overage_rules\x18\x01 \x03(\x0b\x32!.chromiumos.test.api.CoverageRule2\x9e\x08\n\x0bTestService\x12\x87\x01\n\x1a\x42uildTestServiceContainers\x12/.chromite.api.BuildTestServiceContainersRequest\x1a\x30.chromite.api.BuildTestServiceContainersResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x12r\n\x13\x42uildTargetUnitTest\x12(.chromite.api.BuildTargetUnitTestRequest\x1a).chromite.api.BuildTargetUnitTestResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x12\x61\n\x10\x43hromiteUnitTest\x12%.chromite.api.ChromiteUnitTestRequest\x1a&.chromite.api.ChromiteUnitTestResponse\x12[\n\x0e\x43hromitePytest\x12#.chromite.api.ChromitePytestRequest\x1a$.chromite.api.ChromitePytestResponse\x12^\n\x0f\x43rosSigningTest\x12$.chromite.api.CrosSigningTestRequest\x1a%.chromite.api.CrosSigningTestResponse\x12X\n\rDebugInfoTest\x12\".chromite.api.DebugInfoTestRequest\x1a#.chromite.api.DebugInfoTestResponse\x12\x43\n\x06VmTest\x12\x1b.chromite.api.VmTestRequest\x1a\x1c.chromite.api.VmTestResponse\x12]\n\x0cMoblabVmTest\x12!.chromite.api.MoblabVmTestRequest\x1a\".chromite.api.MoblabVmTestResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x12\x81\x01\n\x18SimpleChromeWorkflowTest\x12-.chromite.api.SimpleChromeWorkflowTestRequest\x1a..chromite.api.SimpleChromeWorkflowTestResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x12\x61\n\x10GetCoverageRules\x12%.chromite.api.GetCoverageRulesRequest\x1a&.chromite.api.GetCoverageRulesResponse\x1a\x0c\xc2\xed\x1a\x08\n\x04test\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
+  serialized_pb=b'\n\x17\x63hromite/api/test.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x1a\x63hromite/api/sysroot.proto\x1a\x17\x63hromiumos/common.proto\x1a\x18\x63hromiumos/metrics.proto\x1a-chromiumos/build/api/container_metadata.proto\"\xcf\x02\n\x1fTestServiceContainerBuildResult\x12\x0c\n\x04name\x18\x01 \x01(\t\x12H\n\x07success\x18\x02 \x01(\x0b\x32\x35.chromite.api.TestServiceContainerBuildResult.SuccessH\x00\x12H\n\x07\x66\x61ilure\x18\x03 \x01(\x0b\x32\x35.chromite.api.TestServiceContainerBuildResult.FailureH\x00\x1a^\n\x07Success\x12<\n\nimage_info\x18\x02 \x01(\x0b\x32(.chromiumos.build.api.ContainerImageInfo\x12\x15\n\rregistry_path\x18\x01 \x01(\t\x1a \n\x07\x46\x61ilure\x12\x15\n\rerror_message\x18\x01 \x01(\tB\x08\n\x06result\"\xca\x02\n!BuildTestServiceContainersRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x0f\n\x07version\x18\x03 \x01(\t\x12\x37\n\nrepository\x18\x04 \x01(\x0b\x32#.chromiumos.build.api.GcrRepository\x12\x0c\n\x04tags\x18\x05 \x03(\t\x12K\n\x06labels\x18\x06 \x03(\x0b\x32;.chromite.api.BuildTestServiceContainersRequest.LabelsEntry\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"d\n\"BuildTestServiceContainersResponse\x12>\n\x07results\x18\x01 \x03(\x0b\x32-.chromite.api.TestServiceContainerBuildResult\"\xc0\x03\n\x1a\x42uildTargetUnitTestRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x13\n\x0bresult_path\x18\x02 \x01(\t\x12\"\n\x06\x63hroot\x18\x03 \x01(\x0b\x32\x12.chromiumos.Chroot\x12=\n\x05\x66lags\x18\x04 \x01(\x0b\x32..chromite.api.BuildTargetUnitTestRequest.Flags\x12)\n\x08packages\x18\x06 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\x32\n\x11package_blocklist\x18\x07 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x1a\x95\x01\n\x05\x46lags\x12\x15\n\rempty_sysroot\x18\x01 \x01(\x08\x12\x19\n\x11toolchain_changed\x18\x02 \x01(\x08\x12\x15\n\rcode_coverage\x18\x03 \x01(\x08\x12\"\n\x1atestable_packages_optional\x18\x04 \x01(\x08\x12\x1f\n\x17\x66ilter_only_cros_workon\x18\x05 \x01(\x08J\x04\x08\x05\x10\x06\"\xcc\x01\n\x1b\x42uildTargetUnitTestResponse\x12\x14\n\x0ctarball_path\x18\x01 \x01(\t\x12\x30\n\x0f\x66\x61iled_packages\x18\x02 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\'\n\x06\x65vents\x18\x03 \x03(\x0b\x32\x17.chromiumos.MetricEvent\x12<\n\x13\x66\x61iled_package_data\x18\x04 \x03(\x0b\x32\x1f.chromite.api.FailedPackageData\"=\n\x17\x43hromiteUnitTestRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x1a\n\x18\x43hromiteUnitTestResponse\";\n\x15\x43hromitePytestRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x18\n\x16\x43hromitePytestResponse\"<\n\x16\x43rosSigningTestRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x19\n\x17\x43rosSigningTestResponse\"b\n\x14\x44\x65\x62ugInfoTestRequest\x12&\n\x07sysroot\x18\x01 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x17\n\x15\x44\x65\x62ugInfoTestResponse\"\xd2\x03\n\rVmTestRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12!\n\x07vm_path\x18\x03 \x01(\x0b\x32\x10.chromiumos.Path\x12;\n\x0bssh_options\x18\x04 \x01(\x0b\x32&.chromite.api.VmTestRequest.SshOptions\x12=\n\x0ctest_harness\x18\x05 \x01(\x0e\x32\'.chromite.api.VmTestRequest.TestHarness\x12\x34\n\x08vm_tests\x18\x06 \x03(\x0b\x32\".chromite.api.VmTestRequest.VmTest\x1a\x46\n\nSshOptions\x12*\n\x10private_key_path\x18\x01 \x01(\x0b\x32\x10.chromiumos.Path\x12\x0c\n\x04port\x18\x02 \x01(\x05\x1a\x19\n\x06VmTest\x12\x0f\n\x07pattern\x18\x01 \x01(\t\"6\n\x0bTestHarness\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x08\n\x04TAST\x10\x01\x12\x0c\n\x08\x41UTOTEST\x10\x02\"\x10\n\x0eVmTestResponse\"\xe9\x01\n\x13MoblabVmTestRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12@\n\rimage_payload\x18\x02 \x01(\x0b\x32).chromite.api.MoblabVmTestRequest.Payload\x12\x41\n\x0e\x63\x61\x63he_payloads\x18\x03 \x03(\x0b\x32).chromite.api.MoblabVmTestRequest.Payload\x1a)\n\x07Payload\x12\x1e\n\x04path\x18\x01 \x01(\x0b\x32\x10.chromiumos.Path\"\x16\n\x14MoblabVmTestResponse\"\x8b\x01\n\x1fSimpleChromeWorkflowTestRequest\x12&\n\x07sysroot\x18\x01 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\x13\n\x0b\x63hrome_root\x18\x02 \x01(\t\x12+\n\x0bgoma_config\x18\x03 \x01(\x0b\x32\x16.chromiumos.GomaConfig\"\"\n SimpleChromeWorkflowTestResponse2\xbb\x07\n\x0bTestService\x12\x87\x01\n\x1a\x42uildTestServiceContainers\x12/.chromite.api.BuildTestServiceContainersRequest\x1a\x30.chromite.api.BuildTestServiceContainersResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x12r\n\x13\x42uildTargetUnitTest\x12(.chromite.api.BuildTargetUnitTestRequest\x1a).chromite.api.BuildTargetUnitTestResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x12\x61\n\x10\x43hromiteUnitTest\x12%.chromite.api.ChromiteUnitTestRequest\x1a&.chromite.api.ChromiteUnitTestResponse\x12[\n\x0e\x43hromitePytest\x12#.chromite.api.ChromitePytestRequest\x1a$.chromite.api.ChromitePytestResponse\x12^\n\x0f\x43rosSigningTest\x12$.chromite.api.CrosSigningTestRequest\x1a%.chromite.api.CrosSigningTestResponse\x12X\n\rDebugInfoTest\x12\".chromite.api.DebugInfoTestRequest\x1a#.chromite.api.DebugInfoTestResponse\x12\x43\n\x06VmTest\x12\x1b.chromite.api.VmTestRequest\x1a\x1c.chromite.api.VmTestResponse\x12]\n\x0cMoblabVmTest\x12!.chromite.api.MoblabVmTestRequest\x1a\".chromite.api.MoblabVmTestResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x12\x81\x01\n\x18SimpleChromeWorkflowTest\x12-.chromite.api.SimpleChromeWorkflowTestRequest\x1a..chromite.api.SimpleChromeWorkflowTestResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x1a\x0c\xc2\xed\x1a\x08\n\x04test\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
   ,
-  dependencies=[chromite_dot_api_dot_build__api__pb2.DESCRIPTOR,chromite_dot_api_dot_sysroot__pb2.DESCRIPTOR,chromiumos_dot_common__pb2.DESCRIPTOR,chromiumos_dot_metrics__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_coverage__rule__pb2.DESCRIPTOR,chromiumos_dot_build_dot_api_dot_container__metadata__pb2.DESCRIPTOR,chromiumos_dot_test_dot_plan_dot_source__test__plan__pb2.DESCRIPTOR,])
+  dependencies=[chromite_dot_api_dot_build__api__pb2.DESCRIPTOR,chromite_dot_api_dot_sysroot__pb2.DESCRIPTOR,chromiumos_dot_common__pb2.DESCRIPTOR,chromiumos_dot_metrics__pb2.DESCRIPTOR,chromiumos_dot_build_dot_api_dot_container__metadata__pb2.DESCRIPTOR,])
 
 
 
@@ -57,8 +55,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2457,
-  serialized_end=2511,
+  serialized_start=2433,
+  serialized_end=2487,
 )
 _sym_db.RegisterEnumDescriptor(_VMTESTREQUEST_TESTHARNESS)
 
@@ -97,8 +95,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=481,
-  serialized_end=575,
+  serialized_start=395,
+  serialized_end=489,
 )
 
 _TESTSERVICECONTAINERBUILDRESULT_FAILURE = _descriptor.Descriptor(
@@ -128,8 +126,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=577,
-  serialized_end=609,
+  serialized_start=491,
+  serialized_end=523,
 )
 
 _TESTSERVICECONTAINERBUILDRESULT = _descriptor.Descriptor(
@@ -178,8 +176,8 @@
       create_key=_descriptor._internal_create_key,
     fields=[]),
   ],
-  serialized_start=284,
-  serialized_end=619,
+  serialized_start=198,
+  serialized_end=533,
 )
 
 
@@ -217,8 +215,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=907,
-  serialized_end=952,
+  serialized_start=821,
+  serialized_end=866,
 )
 
 _BUILDTESTSERVICECONTAINERSREQUEST = _descriptor.Descriptor(
@@ -283,8 +281,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=622,
-  serialized_end=952,
+  serialized_start=536,
+  serialized_end=866,
 )
 
 
@@ -315,8 +313,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=954,
-  serialized_end=1054,
+  serialized_start=868,
+  serialized_end=968,
 )
 
 
@@ -375,8 +373,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1350,
-  serialized_end=1499,
+  serialized_start=1264,
+  serialized_end=1413,
 )
 
 _BUILDTARGETUNITTESTREQUEST = _descriptor.Descriptor(
@@ -441,8 +439,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1057,
-  serialized_end=1505,
+  serialized_start=971,
+  serialized_end=1419,
 )
 
 
@@ -475,6 +473,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='failed_package_data', full_name='chromite.api.BuildTargetUnitTestResponse.failed_package_data', index=3,
+      number=4, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -487,8 +492,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1508,
-  serialized_end=1650,
+  serialized_start=1422,
+  serialized_end=1626,
 )
 
 
@@ -519,8 +524,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1652,
-  serialized_end=1713,
+  serialized_start=1628,
+  serialized_end=1689,
 )
 
 
@@ -544,8 +549,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1715,
-  serialized_end=1741,
+  serialized_start=1691,
+  serialized_end=1717,
 )
 
 
@@ -576,8 +581,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1743,
-  serialized_end=1802,
+  serialized_start=1719,
+  serialized_end=1778,
 )
 
 
@@ -601,8 +606,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1804,
-  serialized_end=1828,
+  serialized_start=1780,
+  serialized_end=1804,
 )
 
 
@@ -633,8 +638,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1830,
-  serialized_end=1890,
+  serialized_start=1806,
+  serialized_end=1866,
 )
 
 
@@ -658,8 +663,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1892,
-  serialized_end=1917,
+  serialized_start=1868,
+  serialized_end=1893,
 )
 
 
@@ -697,8 +702,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1919,
-  serialized_end=2017,
+  serialized_start=1895,
+  serialized_end=1993,
 )
 
 
@@ -722,8 +727,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2019,
-  serialized_end=2042,
+  serialized_start=1995,
+  serialized_end=2018,
 )
 
 
@@ -761,8 +766,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2358,
-  serialized_end=2428,
+  serialized_start=2334,
+  serialized_end=2404,
 )
 
 _VMTESTREQUEST_VMTEST = _descriptor.Descriptor(
@@ -792,8 +797,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2430,
-  serialized_end=2455,
+  serialized_start=2406,
+  serialized_end=2431,
 )
 
 _VMTESTREQUEST = _descriptor.Descriptor(
@@ -859,8 +864,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2045,
-  serialized_end=2511,
+  serialized_start=2021,
+  serialized_end=2487,
 )
 
 
@@ -884,8 +889,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2513,
-  serialized_end=2529,
+  serialized_start=2489,
+  serialized_end=2505,
 )
 
 
@@ -916,8 +921,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2724,
-  serialized_end=2765,
+  serialized_start=2700,
+  serialized_end=2741,
 )
 
 _MOBLABVMTESTREQUEST = _descriptor.Descriptor(
@@ -961,8 +966,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2532,
-  serialized_end=2765,
+  serialized_start=2508,
+  serialized_end=2741,
 )
 
 
@@ -986,8 +991,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2767,
-  serialized_end=2789,
+  serialized_start=2743,
+  serialized_end=2765,
 )
 
 
@@ -1032,8 +1037,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2792,
-  serialized_end=2931,
+  serialized_start=2768,
+  serialized_end=2907,
 )
 
 
@@ -1057,100 +1062,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2933,
-  serialized_end=2967,
-)
-
-
-_GETCOVERAGERULESREQUEST = _descriptor.Descriptor(
-  name='GetCoverageRulesRequest',
-  full_name='chromite.api.GetCoverageRulesRequest',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  create_key=_descriptor._internal_create_key,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='chroot', full_name='chromite.api.GetCoverageRulesRequest.chroot', index=0,
-      number=5, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='source_test_plans', full_name='chromite.api.GetCoverageRulesRequest.source_test_plans', index=1,
-      number=1, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='build_metadata_list', full_name='chromite.api.GetCoverageRulesRequest.build_metadata_list', index=2,
-      number=2, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='dut_attribute_list', full_name='chromite.api.GetCoverageRulesRequest.dut_attribute_list', index=3,
-      number=3, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='flat_config_list', full_name='chromite.api.GetCoverageRulesRequest.flat_config_list', index=4,
-      number=4, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=2970,
-  serialized_end=3233,
-)
-
-
-_GETCOVERAGERULESRESPONSE = _descriptor.Descriptor(
-  name='GetCoverageRulesResponse',
-  full_name='chromite.api.GetCoverageRulesResponse',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  create_key=_descriptor._internal_create_key,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='coverage_rules', full_name='chromite.api.GetCoverageRulesResponse.coverage_rules', index=0,
-      number=1, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=3235,
-  serialized_end=3320,
+  serialized_start=2909,
+  serialized_end=2943,
 )
 
 _TESTSERVICECONTAINERBUILDRESULT_SUCCESS.fields_by_name['image_info'].message_type = chromiumos_dot_build_dot_api_dot_container__metadata__pb2._CONTAINERIMAGEINFO
@@ -1178,6 +1091,7 @@
 _BUILDTARGETUNITTESTREQUEST.fields_by_name['package_blocklist'].message_type = chromiumos_dot_common__pb2._PACKAGEINFO
 _BUILDTARGETUNITTESTRESPONSE.fields_by_name['failed_packages'].message_type = chromiumos_dot_common__pb2._PACKAGEINFO
 _BUILDTARGETUNITTESTRESPONSE.fields_by_name['events'].message_type = chromiumos_dot_metrics__pb2._METRICEVENT
+_BUILDTARGETUNITTESTRESPONSE.fields_by_name['failed_package_data'].message_type = chromite_dot_api_dot_sysroot__pb2._FAILEDPACKAGEDATA
 _CHROMITEUNITTESTREQUEST.fields_by_name['chroot'].message_type = chromiumos_dot_common__pb2._CHROOT
 _CHROMITEPYTESTREQUEST.fields_by_name['chroot'].message_type = chromiumos_dot_common__pb2._CHROOT
 _CROSSIGNINGTESTREQUEST.fields_by_name['chroot'].message_type = chromiumos_dot_common__pb2._CHROOT
@@ -1200,12 +1114,6 @@
 _MOBLABVMTESTREQUEST.fields_by_name['cache_payloads'].message_type = _MOBLABVMTESTREQUEST_PAYLOAD
 _SIMPLECHROMEWORKFLOWTESTREQUEST.fields_by_name['sysroot'].message_type = chromite_dot_api_dot_sysroot__pb2._SYSROOT
 _SIMPLECHROMEWORKFLOWTESTREQUEST.fields_by_name['goma_config'].message_type = chromiumos_dot_common__pb2._GOMACONFIG
-_GETCOVERAGERULESREQUEST.fields_by_name['chroot'].message_type = chromiumos_dot_common__pb2._CHROOT
-_GETCOVERAGERULESREQUEST.fields_by_name['source_test_plans'].message_type = chromiumos_dot_test_dot_plan_dot_source__test__plan__pb2._SOURCETESTPLAN
-_GETCOVERAGERULESREQUEST.fields_by_name['build_metadata_list'].message_type = chromiumos_dot_common__pb2._PATH
-_GETCOVERAGERULESREQUEST.fields_by_name['dut_attribute_list'].message_type = chromiumos_dot_common__pb2._PATH
-_GETCOVERAGERULESREQUEST.fields_by_name['flat_config_list'].message_type = chromiumos_dot_common__pb2._PATH
-_GETCOVERAGERULESRESPONSE.fields_by_name['coverage_rules'].message_type = chromiumos_dot_test_dot_api_dot_coverage__rule__pb2._COVERAGERULE
 DESCRIPTOR.message_types_by_name['TestServiceContainerBuildResult'] = _TESTSERVICECONTAINERBUILDRESULT
 DESCRIPTOR.message_types_by_name['BuildTestServiceContainersRequest'] = _BUILDTESTSERVICECONTAINERSREQUEST
 DESCRIPTOR.message_types_by_name['BuildTestServiceContainersResponse'] = _BUILDTESTSERVICECONTAINERSRESPONSE
@@ -1225,8 +1133,6 @@
 DESCRIPTOR.message_types_by_name['MoblabVmTestResponse'] = _MOBLABVMTESTRESPONSE
 DESCRIPTOR.message_types_by_name['SimpleChromeWorkflowTestRequest'] = _SIMPLECHROMEWORKFLOWTESTREQUEST
 DESCRIPTOR.message_types_by_name['SimpleChromeWorkflowTestResponse'] = _SIMPLECHROMEWORKFLOWTESTRESPONSE
-DESCRIPTOR.message_types_by_name['GetCoverageRulesRequest'] = _GETCOVERAGERULESREQUEST
-DESCRIPTOR.message_types_by_name['GetCoverageRulesResponse'] = _GETCOVERAGERULESRESPONSE
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
 TestServiceContainerBuildResult = _reflection.GeneratedProtocolMessageType('TestServiceContainerBuildResult', (_message.Message,), {
@@ -1418,20 +1324,6 @@
   })
 _sym_db.RegisterMessage(SimpleChromeWorkflowTestResponse)
 
-GetCoverageRulesRequest = _reflection.GeneratedProtocolMessageType('GetCoverageRulesRequest', (_message.Message,), {
-  'DESCRIPTOR' : _GETCOVERAGERULESREQUEST,
-  '__module__' : 'chromite.api.test_pb2'
-  # @@protoc_insertion_point(class_scope:chromite.api.GetCoverageRulesRequest)
-  })
-_sym_db.RegisterMessage(GetCoverageRulesRequest)
-
-GetCoverageRulesResponse = _reflection.GeneratedProtocolMessageType('GetCoverageRulesResponse', (_message.Message,), {
-  'DESCRIPTOR' : _GETCOVERAGERULESRESPONSE,
-  '__module__' : 'chromite.api.test_pb2'
-  # @@protoc_insertion_point(class_scope:chromite.api.GetCoverageRulesResponse)
-  })
-_sym_db.RegisterMessage(GetCoverageRulesResponse)
-
 
 DESCRIPTOR._options = None
 _BUILDTESTSERVICECONTAINERSREQUEST_LABELSENTRY._options = None
@@ -1443,8 +1335,8 @@
   index=0,
   serialized_options=b'\302\355\032\010\n\004test\020\001',
   create_key=_descriptor._internal_create_key,
-  serialized_start=3323,
-  serialized_end=4377,
+  serialized_start=2946,
+  serialized_end=3901,
   methods=[
   _descriptor.MethodDescriptor(
     name='BuildTestServiceContainers',
@@ -1536,16 +1428,6 @@
     serialized_options=b'\302\355\032\002\020\002',
     create_key=_descriptor._internal_create_key,
   ),
-  _descriptor.MethodDescriptor(
-    name='GetCoverageRules',
-    full_name='chromite.api.TestService.GetCoverageRules',
-    index=9,
-    containing_service=None,
-    input_type=_GETCOVERAGERULESREQUEST,
-    output_type=_GETCOVERAGERULESRESPONSE,
-    serialized_options=None,
-    create_key=_descriptor._internal_create_key,
-  ),
 ])
 _sym_db.RegisterServiceDescriptor(_TESTSERVICE)
 
diff --git a/api/gen/chromite/api/toolchain_pb2.py b/api/gen/chromite/api/toolchain_pb2.py
index 51d3a2e..29d7b57 100644
--- a/api/gen/chromite/api/toolchain_pb2.py
+++ b/api/gen/chromite/api/toolchain_pb2.py
@@ -2,7 +2,6 @@
 # Generated by the protocol buffer compiler.  DO NOT EDIT!
 # source: chromite/api/toolchain.proto
 """Generated protocol buffer code."""
-from chromite.third_party.google.protobuf.internal import enum_type_wrapper
 from chromite.third_party.google.protobuf import descriptor as _descriptor
 from chromite.third_party.google.protobuf import message as _message
 from chromite.third_party.google.protobuf import reflection as _reflection
@@ -25,57 +24,41 @@
   syntax='proto3',
   serialized_options=b'Z6go.chromium.org/chromiumos/infra/proto/go/chromite/api',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n\x1c\x63hromite/api/toolchain.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/artifacts.proto\x1a\x1c\x63hromite/api/build_api.proto\x1a\x1a\x63hromite/api/sysroot.proto\x1a\x1f\x63hromiumos/builder_config.proto\x1a\x17\x63hromiumos/common.proto\"\x83\x01\n\x0c\x41rtifactInfo\x12H\n\rartifact_type\x18\x01 \x01(\x0e\x32\x31.chromiumos.BuilderConfig.Artifacts.ArtifactTypes\x12)\n\tartifacts\x18\x02 \x03(\x0b\x32\x16.chromite.api.Artifact\"\x83\x03\n\x1fPrepareForToolchainBuildRequest\x12I\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x31.chromiumos.BuilderConfig.Artifacts.ArtifactTypes\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x03 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12N\n\x0finput_artifacts\x18\x04 \x03(\x0b\x32\x35.chromiumos.BuilderConfig.Artifacts.InputArtifactInfo\x12\x42\n\x0f\x61\x64\x64itional_args\x18\x05 \x01(\x0b\x32).chromiumos.PrepareForBuildAdditionalArgs\x12\x35\n\x0cprofile_info\x18\x06 \x01(\x0b\x32\x1f.chromiumos.ArtifactProfileInfo\"q\n PrepareForToolchainBuildResponse\x12M\n\x0f\x62uild_relevance\x18\x01 \x01(\x0e\x32\x34.chromite.api.PrepareForBuildResponse.BuildRelevance\"\xbe\x02\n\x16\x42undleToolchainRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\x12\n\noutput_dir\x18\x03 \x01(\t\x12I\n\x0e\x61rtifact_types\x18\x04 \x03(\x0e\x32\x31.chromiumos.BuilderConfig.Artifacts.ArtifactTypes\x12\x42\n\x0f\x61\x64\x64itional_args\x18\x05 \x01(\x0b\x32).chromiumos.PrepareForBuildAdditionalArgs\x12\x35\n\x0cprofile_info\x18\x06 \x01(\x0b\x32\x1f.chromiumos.ArtifactProfileInfo\"S\n\x17\x42undleToolchainResponse\x12\x32\n\x0e\x61rtifacts_info\x18\x02 \x03(\x0b\x32\x1a.chromite.api.ArtifactInfoJ\x04\x08\x01\x10\x02\"\xeb\x01\n\x16GetUpdatedFilesRequest\x12R\n\x12uploaded_artifacts\x18\x01 \x03(\x0b\x32\x36.chromite.api.GetUpdatedFilesRequest.UploadedArtifacts\x1a}\n\x11UploadedArtifacts\x12\x31\n\rartifact_info\x18\x01 \x01(\x0b\x32\x1a.chromite.api.ArtifactInfo\x12\x35\n\x0cprofile_info\x18\x02 \x01(\x0b\x32\x1f.chromiumos.ArtifactProfileInfo\"\xf4\x03\n\x17GetUpdatedFilesResponse\x12H\n\rupdated_files\x18\x01 \x03(\x0b\x32\x31.chromite.api.GetUpdatedFilesResponse.UpdatedFile\x12\x16\n\x0e\x63ommit_message\x18\x02 \x01(\t\x12I\n\rcommit_footer\x18\x03 \x03(\x0b\x32\x32.chromite.api.GetUpdatedFilesResponse.CommitFooter\x1a\x1b\n\x0bUpdatedFile\x12\x0c\n\x04path\x18\x01 \x01(\t\x1a\x41\n\x0e\x43qDependFooter\x12/\n\rgerrit_change\x18\x01 \x03(\x0b\x32\x18.chromiumos.GerritChange\x1a\x1c\n\rCqClTagFooter\x12\x0b\n\x03tag\x18\x01 \x01(\t\x1a\xad\x01\n\x0c\x43ommitFooter\x12I\n\tcq_depend\x18\x01 \x01(\x0b\x32\x34.chromite.api.GetUpdatedFilesResponse.CqDependFooterH\x00\x12H\n\tcq_cl_tag\x18\x02 \x01(\x0b\x32\x33.chromite.api.GetUpdatedFilesResponse.CqClTagFooterH\x00\x42\x08\n\x06\x66ooter\"\x80\x01\n\x1aVerifyAFDOArtifactsRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x33\n\rartifact_type\x18\x02 \x01(\x0e\x32\x1c.chromiumos.AFDOArtifactType\"-\n\x1bVerifyAFDOArtifactsResponse\x12\x0e\n\x06status\x18\x01 \x01(\x08\"X\n\rLinterFinding\x12\x0f\n\x07message\x18\x01 \x01(\t\x12\x36\n\tlocations\x18\x02 \x03(\x0b\x32#.chromite.api.LinterFindingLocation\"O\n\x15LinterFindingLocation\x12\x10\n\x08\x66ilepath\x18\x01 \x01(\t\x12\x12\n\nline_start\x18\x02 \x01(\x05\x12\x10\n\x08line_end\x18\x03 \x01(\x05\"\x86\x01\n\rLinterRequest\x12)\n\x08packages\x18\x01 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\"\n\x06\x63hroot\x18\x03 \x01(\x0b\x32\x12.chromiumos.Chroot\"?\n\x0eLinterResponse\x12-\n\x08\x66indings\x18\x01 \x03(\x0b\x32\x1b.chromite.api.LinterFinding*f\n\x10\x41\x46\x44OArtifactType\x12\r\n\tNONE_TYPE\x10\x00\x12\r\n\tORDERFILE\x10\x01\x12\x12\n\x0e\x42\x45NCHMARK_AFDO\x10\x02\x12\x0f\n\x0bKERNEL_AFDO\x10\x03\x12\x0f\n\x0b\x43HROME_AFDO\x10\x04\x32\xa4\x05\n\x10ToolchainService\x12|\n\x1dUpdateEbuildWithAFDOArtifacts\x12(.chromite.api.VerifyAFDOArtifactsRequest\x1a).chromite.api.VerifyAFDOArtifactsResponse\"\x06\xc2\xed\x1a\x02\x10\x01\x12x\n\x19UploadVettedAFDOArtifacts\x12(.chromite.api.VerifyAFDOArtifactsRequest\x1a).chromite.api.VerifyAFDOArtifactsResponse\"\x06\xc2\xed\x1a\x02\x10\x01\x12p\n\x0fPrepareForBuild\x12-.chromite.api.PrepareForToolchainBuildRequest\x1a..chromite.api.PrepareForToolchainBuildResponse\x12^\n\x0f\x42undleArtifacts\x12$.chromite.api.BundleToolchainRequest\x1a%.chromite.api.BundleToolchainResponse\x12^\n\x0fGetUpdatedFiles\x12$.chromite.api.GetUpdatedFilesRequest\x1a%.chromite.api.GetUpdatedFilesResponse\x12S\n\x0eGetClippyLints\x12\x1b.chromite.api.LinterRequest\x1a\x1c.chromite.api.LinterResponse\"\x06\xc2\xed\x1a\x02\x10\x01\x1a\x11\xc2\xed\x1a\r\n\ttoolchain\x10\x02\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
+  serialized_pb=b'\n\x1c\x63hromite/api/toolchain.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/artifacts.proto\x1a\x1c\x63hromite/api/build_api.proto\x1a\x1a\x63hromite/api/sysroot.proto\x1a\x1f\x63hromiumos/builder_config.proto\x1a\x17\x63hromiumos/common.proto\"\x83\x01\n\x0c\x41rtifactInfo\x12H\n\rartifact_type\x18\x01 \x01(\x0e\x32\x31.chromiumos.BuilderConfig.Artifacts.ArtifactTypes\x12)\n\tartifacts\x18\x02 \x03(\x0b\x32\x16.chromite.api.Artifact\"\x83\x03\n\x1fPrepareForToolchainBuildRequest\x12I\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x31.chromiumos.BuilderConfig.Artifacts.ArtifactTypes\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x03 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12N\n\x0finput_artifacts\x18\x04 \x03(\x0b\x32\x35.chromiumos.BuilderConfig.Artifacts.InputArtifactInfo\x12\x42\n\x0f\x61\x64\x64itional_args\x18\x05 \x01(\x0b\x32).chromiumos.PrepareForBuildAdditionalArgs\x12\x35\n\x0cprofile_info\x18\x06 \x01(\x0b\x32\x1f.chromiumos.ArtifactProfileInfo\"q\n PrepareForToolchainBuildResponse\x12M\n\x0f\x62uild_relevance\x18\x01 \x01(\x0e\x32\x34.chromite.api.PrepareForBuildResponse.BuildRelevance\"\xbe\x02\n\x16\x42undleToolchainRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\x12\n\noutput_dir\x18\x03 \x01(\t\x12I\n\x0e\x61rtifact_types\x18\x04 \x03(\x0e\x32\x31.chromiumos.BuilderConfig.Artifacts.ArtifactTypes\x12\x42\n\x0f\x61\x64\x64itional_args\x18\x05 \x01(\x0b\x32).chromiumos.PrepareForBuildAdditionalArgs\x12\x35\n\x0cprofile_info\x18\x06 \x01(\x0b\x32\x1f.chromiumos.ArtifactProfileInfo\"S\n\x17\x42undleToolchainResponse\x12\x32\n\x0e\x61rtifacts_info\x18\x02 \x03(\x0b\x32\x1a.chromite.api.ArtifactInfoJ\x04\x08\x01\x10\x02\"\xeb\x01\n\x16GetUpdatedFilesRequest\x12R\n\x12uploaded_artifacts\x18\x01 \x03(\x0b\x32\x36.chromite.api.GetUpdatedFilesRequest.UploadedArtifacts\x1a}\n\x11UploadedArtifacts\x12\x31\n\rartifact_info\x18\x01 \x01(\x0b\x32\x1a.chromite.api.ArtifactInfo\x12\x35\n\x0cprofile_info\x18\x02 \x01(\x0b\x32\x1f.chromiumos.ArtifactProfileInfo\"\xf4\x03\n\x17GetUpdatedFilesResponse\x12H\n\rupdated_files\x18\x01 \x03(\x0b\x32\x31.chromite.api.GetUpdatedFilesResponse.UpdatedFile\x12\x16\n\x0e\x63ommit_message\x18\x02 \x01(\t\x12I\n\rcommit_footer\x18\x03 \x03(\x0b\x32\x32.chromite.api.GetUpdatedFilesResponse.CommitFooter\x1a\x1b\n\x0bUpdatedFile\x12\x0c\n\x04path\x18\x01 \x01(\t\x1a\x41\n\x0e\x43qDependFooter\x12/\n\rgerrit_change\x18\x01 \x03(\x0b\x32\x18.chromiumos.GerritChange\x1a\x1c\n\rCqClTagFooter\x12\x0b\n\x03tag\x18\x01 \x01(\t\x1a\xad\x01\n\x0c\x43ommitFooter\x12I\n\tcq_depend\x18\x01 \x01(\x0b\x32\x34.chromite.api.GetUpdatedFilesResponse.CqDependFooterH\x00\x12H\n\tcq_cl_tag\x18\x02 \x01(\x0b\x32\x33.chromite.api.GetUpdatedFilesResponse.CqClTagFooterH\x00\x42\x08\n\x06\x66ooter\"\xd2\x01\n\rLinterFinding\x12\x0f\n\x07message\x18\x01 \x01(\t\x12\x36\n\tlocations\x18\x02 \x03(\x0b\x32#.chromite.api.LinterFindingLocation\x12\x33\n\x06linter\x18\x03 \x01(\x0e\x32#.chromite.api.LinterFinding.Linters\"C\n\x07Linters\x12\x16\n\x12LINTER_UNSPECIFIED\x10\x00\x12\x0e\n\nCLANG_TIDY\x10\x01\x12\x10\n\x0c\x43\x41RGO_CLIPPY\x10\x02\"O\n\x15LinterFindingLocation\x12\x10\n\x08\x66ilepath\x18\x01 \x01(\t\x12\x12\n\nline_start\x18\x02 \x01(\x05\x12\x10\n\x08line_end\x18\x03 \x01(\x05\"\x86\x01\n\rLinterRequest\x12)\n\x08packages\x18\x01 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\"\n\x06\x63hroot\x18\x03 \x01(\x0b\x32\x12.chromiumos.Chroot\"?\n\x0eLinterResponse\x12-\n\x08\x66indings\x18\x01 \x03(\x0b\x32\x1b.chromite.api.LinterFinding2\x84\x04\n\x10ToolchainService\x12p\n\x0fPrepareForBuild\x12-.chromite.api.PrepareForToolchainBuildRequest\x1a..chromite.api.PrepareForToolchainBuildResponse\x12^\n\x0f\x42undleArtifacts\x12$.chromite.api.BundleToolchainRequest\x1a%.chromite.api.BundleToolchainResponse\x12^\n\x0fGetUpdatedFiles\x12$.chromite.api.GetUpdatedFilesRequest\x1a%.chromite.api.GetUpdatedFilesResponse\x12V\n\x11\x45mergeWithLinting\x12\x1b.chromite.api.LinterRequest\x1a\x1c.chromite.api.LinterResponse\"\x06\xc2\xed\x1a\x02\x10\x01\x12S\n\x0eGetClippyLints\x12\x1b.chromite.api.LinterRequest\x1a\x1c.chromite.api.LinterResponse\"\x06\xc2\xed\x1a\x02\x10\x01\x1a\x11\xc2\xed\x1a\r\n\ttoolchain\x10\x02\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
   ,
   dependencies=[chromite_dot_api_dot_artifacts__pb2.DESCRIPTOR,chromite_dot_api_dot_build__api__pb2.DESCRIPTOR,chromite_dot_api_dot_sysroot__pb2.DESCRIPTOR,chromiumos_dot_builder__config__pb2.DESCRIPTOR,chromiumos_dot_common__pb2.DESCRIPTOR,])
 
-_AFDOARTIFACTTYPE = _descriptor.EnumDescriptor(
-  name='AFDOArtifactType',
-  full_name='chromite.api.AFDOArtifactType',
+
+
+_LINTERFINDING_LINTERS = _descriptor.EnumDescriptor(
+  name='Linters',
+  full_name='chromite.api.LinterFinding.Linters',
   filename=None,
   file=DESCRIPTOR,
   create_key=_descriptor._internal_create_key,
   values=[
     _descriptor.EnumValueDescriptor(
-      name='NONE_TYPE', index=0, number=0,
+      name='LINTER_UNSPECIFIED', index=0, number=0,
       serialized_options=None,
       type=None,
       create_key=_descriptor._internal_create_key),
     _descriptor.EnumValueDescriptor(
-      name='ORDERFILE', index=1, number=1,
+      name='CLANG_TIDY', index=1, number=1,
       serialized_options=None,
       type=None,
       create_key=_descriptor._internal_create_key),
     _descriptor.EnumValueDescriptor(
-      name='BENCHMARK_AFDO', index=2, number=2,
-      serialized_options=None,
-      type=None,
-      create_key=_descriptor._internal_create_key),
-    _descriptor.EnumValueDescriptor(
-      name='KERNEL_AFDO', index=3, number=3,
-      serialized_options=None,
-      type=None,
-      create_key=_descriptor._internal_create_key),
-    _descriptor.EnumValueDescriptor(
-      name='CHROME_AFDO', index=4, number=4,
+      name='CARGO_CLIPPY', index=2, number=2,
       serialized_options=None,
       type=None,
       create_key=_descriptor._internal_create_key),
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2529,
-  serialized_end=2631,
+  serialized_start=2122,
+  serialized_end=2189,
 )
-_sym_db.RegisterEnumDescriptor(_AFDOARTIFACTTYPE)
-
-AFDOArtifactType = enum_type_wrapper.EnumTypeWrapper(_AFDOARTIFACTTYPE)
-NONE_TYPE = 0
-ORDERFILE = 1
-BENCHMARK_AFDO = 2
-KERNEL_AFDO = 3
-CHROME_AFDO = 4
-
+_sym_db.RegisterEnumDescriptor(_LINTERFINDING_LINTERS)
 
 
 _ARTIFACTINFO = _descriptor.Descriptor(
@@ -567,77 +550,6 @@
 )
 
 
-_VERIFYAFDOARTIFACTSREQUEST = _descriptor.Descriptor(
-  name='VerifyAFDOArtifactsRequest',
-  full_name='chromite.api.VerifyAFDOArtifactsRequest',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  create_key=_descriptor._internal_create_key,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='build_target', full_name='chromite.api.VerifyAFDOArtifactsRequest.build_target', index=0,
-      number=1, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='artifact_type', full_name='chromite.api.VerifyAFDOArtifactsRequest.artifact_type', index=1,
-      number=2, type=14, cpp_type=8, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1979,
-  serialized_end=2107,
-)
-
-
-_VERIFYAFDOARTIFACTSRESPONSE = _descriptor.Descriptor(
-  name='VerifyAFDOArtifactsResponse',
-  full_name='chromite.api.VerifyAFDOArtifactsResponse',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  create_key=_descriptor._internal_create_key,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='status', full_name='chromite.api.VerifyAFDOArtifactsResponse.status', index=0,
-      number=1, type=8, cpp_type=7, label=1,
-      has_default_value=False, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=2109,
-  serialized_end=2154,
-)
-
-
 _LINTERFINDING = _descriptor.Descriptor(
   name='LinterFinding',
   full_name='chromite.api.LinterFinding',
@@ -660,11 +572,19 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='linter', full_name='chromite.api.LinterFinding.linter', index=2,
+      number=3, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
   nested_types=[],
   enum_types=[
+    _LINTERFINDING_LINTERS,
   ],
   serialized_options=None,
   is_extendable=False,
@@ -672,8 +592,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2156,
-  serialized_end=2244,
+  serialized_start=1979,
+  serialized_end=2189,
 )
 
 
@@ -718,8 +638,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2246,
-  serialized_end=2325,
+  serialized_start=2191,
+  serialized_end=2270,
 )
 
 
@@ -764,8 +684,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2328,
-  serialized_end=2462,
+  serialized_start=2273,
+  serialized_end=2407,
 )
 
 
@@ -796,8 +716,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2464,
-  serialized_end=2527,
+  serialized_start=2409,
+  serialized_end=2472,
 )
 
 _ARTIFACTINFO.fields_by_name['artifact_type'].enum_type = chromiumos_dot_builder__config__pb2._BUILDERCONFIG_ARTIFACTS_ARTIFACTTYPES
@@ -834,9 +754,9 @@
 _GETUPDATEDFILESRESPONSE_COMMITFOOTER.fields_by_name['cq_cl_tag'].containing_oneof = _GETUPDATEDFILESRESPONSE_COMMITFOOTER.oneofs_by_name['footer']
 _GETUPDATEDFILESRESPONSE.fields_by_name['updated_files'].message_type = _GETUPDATEDFILESRESPONSE_UPDATEDFILE
 _GETUPDATEDFILESRESPONSE.fields_by_name['commit_footer'].message_type = _GETUPDATEDFILESRESPONSE_COMMITFOOTER
-_VERIFYAFDOARTIFACTSREQUEST.fields_by_name['build_target'].message_type = chromiumos_dot_common__pb2._BUILDTARGET
-_VERIFYAFDOARTIFACTSREQUEST.fields_by_name['artifact_type'].enum_type = chromiumos_dot_common__pb2._AFDOARTIFACTTYPE
 _LINTERFINDING.fields_by_name['locations'].message_type = _LINTERFINDINGLOCATION
+_LINTERFINDING.fields_by_name['linter'].enum_type = _LINTERFINDING_LINTERS
+_LINTERFINDING_LINTERS.containing_type = _LINTERFINDING
 _LINTERREQUEST.fields_by_name['packages'].message_type = chromiumos_dot_common__pb2._PACKAGEINFO
 _LINTERREQUEST.fields_by_name['sysroot'].message_type = chromite_dot_api_dot_sysroot__pb2._SYSROOT
 _LINTERREQUEST.fields_by_name['chroot'].message_type = chromiumos_dot_common__pb2._CHROOT
@@ -848,13 +768,10 @@
 DESCRIPTOR.message_types_by_name['BundleToolchainResponse'] = _BUNDLETOOLCHAINRESPONSE
 DESCRIPTOR.message_types_by_name['GetUpdatedFilesRequest'] = _GETUPDATEDFILESREQUEST
 DESCRIPTOR.message_types_by_name['GetUpdatedFilesResponse'] = _GETUPDATEDFILESRESPONSE
-DESCRIPTOR.message_types_by_name['VerifyAFDOArtifactsRequest'] = _VERIFYAFDOARTIFACTSREQUEST
-DESCRIPTOR.message_types_by_name['VerifyAFDOArtifactsResponse'] = _VERIFYAFDOARTIFACTSRESPONSE
 DESCRIPTOR.message_types_by_name['LinterFinding'] = _LINTERFINDING
 DESCRIPTOR.message_types_by_name['LinterFindingLocation'] = _LINTERFINDINGLOCATION
 DESCRIPTOR.message_types_by_name['LinterRequest'] = _LINTERREQUEST
 DESCRIPTOR.message_types_by_name['LinterResponse'] = _LINTERRESPONSE
-DESCRIPTOR.enum_types_by_name['AFDOArtifactType'] = _AFDOARTIFACTTYPE
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
 ArtifactInfo = _reflection.GeneratedProtocolMessageType('ArtifactInfo', (_message.Message,), {
@@ -946,20 +863,6 @@
 _sym_db.RegisterMessage(GetUpdatedFilesResponse.CqClTagFooter)
 _sym_db.RegisterMessage(GetUpdatedFilesResponse.CommitFooter)
 
-VerifyAFDOArtifactsRequest = _reflection.GeneratedProtocolMessageType('VerifyAFDOArtifactsRequest', (_message.Message,), {
-  'DESCRIPTOR' : _VERIFYAFDOARTIFACTSREQUEST,
-  '__module__' : 'chromite.api.toolchain_pb2'
-  # @@protoc_insertion_point(class_scope:chromite.api.VerifyAFDOArtifactsRequest)
-  })
-_sym_db.RegisterMessage(VerifyAFDOArtifactsRequest)
-
-VerifyAFDOArtifactsResponse = _reflection.GeneratedProtocolMessageType('VerifyAFDOArtifactsResponse', (_message.Message,), {
-  'DESCRIPTOR' : _VERIFYAFDOARTIFACTSRESPONSE,
-  '__module__' : 'chromite.api.toolchain_pb2'
-  # @@protoc_insertion_point(class_scope:chromite.api.VerifyAFDOArtifactsResponse)
-  })
-_sym_db.RegisterMessage(VerifyAFDOArtifactsResponse)
-
 LinterFinding = _reflection.GeneratedProtocolMessageType('LinterFinding', (_message.Message,), {
   'DESCRIPTOR' : _LINTERFINDING,
   '__module__' : 'chromite.api.toolchain_pb2'
@@ -998,33 +901,13 @@
   index=0,
   serialized_options=b'\302\355\032\r\n\ttoolchain\020\002',
   create_key=_descriptor._internal_create_key,
-  serialized_start=2634,
-  serialized_end=3310,
+  serialized_start=2475,
+  serialized_end=2991,
   methods=[
   _descriptor.MethodDescriptor(
-    name='UpdateEbuildWithAFDOArtifacts',
-    full_name='chromite.api.ToolchainService.UpdateEbuildWithAFDOArtifacts',
-    index=0,
-    containing_service=None,
-    input_type=_VERIFYAFDOARTIFACTSREQUEST,
-    output_type=_VERIFYAFDOARTIFACTSRESPONSE,
-    serialized_options=b'\302\355\032\002\020\001',
-    create_key=_descriptor._internal_create_key,
-  ),
-  _descriptor.MethodDescriptor(
-    name='UploadVettedAFDOArtifacts',
-    full_name='chromite.api.ToolchainService.UploadVettedAFDOArtifacts',
-    index=1,
-    containing_service=None,
-    input_type=_VERIFYAFDOARTIFACTSREQUEST,
-    output_type=_VERIFYAFDOARTIFACTSRESPONSE,
-    serialized_options=b'\302\355\032\002\020\001',
-    create_key=_descriptor._internal_create_key,
-  ),
-  _descriptor.MethodDescriptor(
     name='PrepareForBuild',
     full_name='chromite.api.ToolchainService.PrepareForBuild',
-    index=2,
+    index=0,
     containing_service=None,
     input_type=_PREPAREFORTOOLCHAINBUILDREQUEST,
     output_type=_PREPAREFORTOOLCHAINBUILDRESPONSE,
@@ -1034,7 +917,7 @@
   _descriptor.MethodDescriptor(
     name='BundleArtifacts',
     full_name='chromite.api.ToolchainService.BundleArtifacts',
-    index=3,
+    index=1,
     containing_service=None,
     input_type=_BUNDLETOOLCHAINREQUEST,
     output_type=_BUNDLETOOLCHAINRESPONSE,
@@ -1044,7 +927,7 @@
   _descriptor.MethodDescriptor(
     name='GetUpdatedFiles',
     full_name='chromite.api.ToolchainService.GetUpdatedFiles',
-    index=4,
+    index=2,
     containing_service=None,
     input_type=_GETUPDATEDFILESREQUEST,
     output_type=_GETUPDATEDFILESRESPONSE,
@@ -1052,9 +935,19 @@
     create_key=_descriptor._internal_create_key,
   ),
   _descriptor.MethodDescriptor(
+    name='EmergeWithLinting',
+    full_name='chromite.api.ToolchainService.EmergeWithLinting',
+    index=3,
+    containing_service=None,
+    input_type=_LINTERREQUEST,
+    output_type=_LINTERRESPONSE,
+    serialized_options=b'\302\355\032\002\020\001',
+    create_key=_descriptor._internal_create_key,
+  ),
+  _descriptor.MethodDescriptor(
     name='GetClippyLints',
     full_name='chromite.api.ToolchainService.GetClippyLints',
-    index=5,
+    index=4,
     containing_service=None,
     input_type=_LINTERREQUEST,
     output_type=_LINTERRESPONSE,
diff --git a/api/gen/chromiumos/build_report_pb2.py b/api/gen/chromiumos/build_report_pb2.py
index 7b29ea7..84e2a78 100644
--- a/api/gen/chromiumos/build_report_pb2.py
+++ b/api/gen/chromiumos/build_report_pb2.py
@@ -21,7 +21,7 @@
   syntax='proto3',
   serialized_options=b'\n!com.google.chrome.crosinfra.protoZ4go.chromium.org/chromiumos/infra/proto/go/chromiumos',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n\x1d\x63hromiumos/build_report.proto\x12\nchromiumos\x1a\x17\x63hromiumos/common.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"_\n\tTimeframe\x12)\n\x05\x62\x65gin\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\'\n\x03\x65nd\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"\xd7\x12\n\x0f\x42uildReportBeta\x12\x18\n\x0e\x62uildbucket_id\x18\x01 \x01(\x03H\x00\x12\x33\n\x04type\x18\x02 \x01(\x0e\x32%.chromiumos.BuildReportBeta.BuildType\x12\x37\n\x06status\x18\x03 \x01(\x0b\x32\'.chromiumos.BuildReportBeta.BuildStatus\x12\x37\n\x06\x63onfig\x18\x04 \x01(\x0b\x32\'.chromiumos.BuildReportBeta.BuildConfig\x12\x36\n\x05steps\x18\x05 \x01(\x0b\x32\'.chromiumos.BuildReportBeta.StepDetails\x12<\n\tartifacts\x18\x07 \x03(\x0b\x32).chromiumos.BuildReportBeta.BuildArtifact\x1a\xf0\x01\n\x0b\x42uildStatus\x12=\n\x05value\x18\x01 \x01(\x0e\x32..chromiumos.BuildReportBeta.BuildStatus.Status\"\xa1\x01\n\x06Status\x12\r\n\tUNDEFINED\x10\x00\x12\x11\n\rKIND_TERMINAL\x10\x01\x12\x10\n\x0cKIND_RUNNING\x10\x02\x12\x0b\n\x07SUCCESS\x10\x64\x12\x0b\n\x07\x46\x41ILURE\x10\x65\x12\x11\n\rINFRA_FAILURE\x10\x66\x12\x0c\n\x08WATCHDOG\x10g\x12\x0c\n\x08\x43\x41NCELED\x10h\x12\x0c\n\x07RUNNING\x10\xc8\x01\x12\x0c\n\x07WAITING\x10\xc9\x01\x1a\xd1\x02\n\x0b\x42uildConfig\x12>\n\x06\x62ranch\x18\x01 \x01(\x0b\x32..chromiumos.BuildReportBeta.BuildConfig.Branch\x12@\n\x07release\x18\x02 \x01(\x0b\x32/.chromiumos.BuildReportBeta.BuildConfig.Release\x12=\n\x06models\x18\x03 \x03(\x0b\x32-.chromiumos.BuildReportBeta.BuildConfig.Model\x1a\x15\n\x05Model\x12\x0c\n\x04name\x18\x01 \x01(\t\x1aR\n\x07Release\x12\x11\n\tmilestone\x18\x01 \x01(\x05\x12\r\n\x05\x62uild\x18\x02 \x01(\t\x12%\n\x08\x63hannels\x18\x03 \x03(\x0e\x32\x13.chromiumos.Channel\x1a\x16\n\x06\x42ranch\x12\x0c\n\x04name\x18\x01 \x01(\t\x1a\xb5\x04\n\rBuildArtifact\x12<\n\x04type\x18\x01 \x01(\x0e\x32..chromiumos.BuildReportBeta.BuildArtifact.Type\x12:\n\x03uri\x18\x02 \x01(\x0b\x32-.chromiumos.BuildReportBeta.BuildArtifact.URI\x12\x0e\n\x06sha256\x18\x03 \x01(\t\x12+\n\x07\x63reated\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x1a\x1b\n\x03URI\x12\r\n\x03gcs\x18\x01 \x01(\tH\x00\x42\x05\n\x03uri\"\xcf\x02\n\x04Type\x12\r\n\tUNDEFINED\x10\x00\x12\x0f\n\x0bIMAGE_TYPES\x10\x01\x12\x12\n\x0e\x46IRMWARE_TYPES\x10\x02\x12\x0e\n\nAFDO_TYPES\x10\x03\x12\x11\n\rRELEASE_IMAGE\x10\x64\x12\x12\n\x0eRECOVERY_IMAGE\x10\x65\x12\r\n\tDLC_IMAGE\x10\x66\x12\x16\n\x12\x44\x45\x42UG_SYMBOL_IMAGE\x10g\x12\x10\n\x0cHWQUAL_IMAGE\x10h\x12\x0e\n\nTEST_IMAGE\x10i\x12\x15\n\x10\x46IRMWARE_TARBALL\x10\xc8\x01\x12\x1a\n\x15\x46IRMWARE_TARBALL_INFO\x10\xc9\x01\x12\x12\n\rFIRMWARE_LCOV\x10\xca\x01\x12\x13\n\x0e\x41\x46\x44O_ORDERFILE\x10\xac\x02\x12\x13\n\x0e\x41\x46\x44O_BENCHMARK\x10\xad\x02\x12\x10\n\x0b\x41\x46\x44O_KERNEL\x10\xae\x02\x12\x10\n\x0b\x41\x46\x44O_CHROME\x10\xaf\x02\x1a\x97\x06\n\x0bStepDetails\x12\x41\n\x07\x63urrent\x18\x01 \x01(\x0e\x32\x30.chromiumos.BuildReportBeta.StepDetails.StepName\x12?\n\x04info\x18\x02 \x03(\x0b\x32\x31.chromiumos.BuildReportBeta.StepDetails.InfoEntry\x1a\x81\x01\n\x08StepInfo\x12\r\n\x05order\x18\x01 \x01(\x05\x12>\n\x06status\x18\x02 \x01(\x0e\x32..chromiumos.BuildReportBeta.StepDetails.Status\x12&\n\x07runtime\x18\x03 \x01(\x0b\x32\x15.chromiumos.Timeframe\x1a]\n\tInfoEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12?\n\x05value\x18\x02 \x01(\x0b\x32\x30.chromiumos.BuildReportBeta.StepDetails.StepInfo:\x02\x38\x01\"\xc9\x01\n\x06Status\x12\x19\n\x15STEP_STATUS_UNDEFINED\x10\x00\x12\x11\n\rKIND_TERMINAL\x10\x01\x12\x10\n\x0cKIND_RUNNING\x10\x02\x12\x12\n\x0eSTATUS_SUCCESS\x10\x64\x12\x12\n\x0eSTATUS_FAILURE\x10\x65\x12\x18\n\x14STATUS_INFRA_FAILURE\x10\x66\x12\x13\n\x0fSTATUS_WATCHDOG\x10g\x12\x13\n\x0fSTATUS_CANCELED\x10h\x12\x13\n\x0eSTATUS_RUNNING\x10\xc8\x01\"\xd4\x01\n\x08StepName\x12\x12\n\x0eSTEP_UNDEFINED\x10\x00\x12\x10\n\x0cSTEP_OVERALL\x10\x64\x12\x0e\n\tSTEP_SYNC\x10\xc8\x01\x12\x15\n\x10STEP_SYNC_CHROME\x10\xc9\x01\x12\r\n\x08STEP_SDK\x10\xac\x02\x12\x12\n\rSTEP_SDK_INIT\x10\xad\x02\x12\x14\n\x0fSTEP_SDK_UPDATE\x10\xae\x02\x12\x0f\n\nSTEP_BUILD\x10\x90\x03\x12\x17\n\x12STEP_BUILD_SYSROOT\x10\x91\x03\x12\x18\n\x13STEP_BUILD_PACKAGES\x10\x92\x03\"n\n\tBuildType\x12\x18\n\x14\x42UILD_TYPE_UNDEFINED\x10\x00\x12\x16\n\x12\x42UILD_TYPE_RELEASE\x10\x01\x12\x17\n\x13\x42UILD_TYPE_FIRMWARE\x10\x02\x12\x16\n\x12\x42UILD_TYPE_FACTORY\x10\x03\x42\x04\n\x02idBY\n!com.google.chrome.crosinfra.protoZ4go.chromium.org/chromiumos/infra/proto/go/chromiumosb\x06proto3'
+  serialized_pb=b'\n\x1d\x63hromiumos/build_report.proto\x12\nchromiumos\x1a\x17\x63hromiumos/common.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"_\n\tTimeframe\x12)\n\x05\x62\x65gin\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\'\n\x03\x65nd\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\")\n\x07\x42uildId\x12\x18\n\x0e\x62uildbucket_id\x18\x01 \x01(\x03H\x00\x42\x04\n\x02id\"\xd2)\n\x0f\x42uildReportBeta\x12\x18\n\x0e\x62uildbucket_id\x18\x01 \x01(\x03H\x00\x12\r\n\x05\x63ount\x18\x08 \x01(\x03\x12#\n\x06parent\x18\t \x01(\x0b\x32\x13.chromiumos.BuildId\x12%\n\x08\x63hildren\x18\n \x03(\x0b\x32\x13.chromiumos.BuildId\x12\x33\n\x04type\x18\x02 \x01(\x0e\x32%.chromiumos.BuildReportBeta.BuildType\x12\x37\n\x06status\x18\x03 \x01(\x0b\x32\'.chromiumos.BuildReportBeta.BuildStatus\x12\x37\n\x06\x63onfig\x18\x04 \x01(\x0b\x32\'.chromiumos.BuildReportBeta.BuildConfig\x12\x36\n\x05steps\x18\x05 \x01(\x0b\x32\'.chromiumos.BuildReportBeta.StepDetails\x12\x46\n\rsigned_builds\x18\x06 \x03(\x0b\x32/.chromiumos.BuildReportBeta.SignedBuildMetadata\x12\x35\n\x08payloads\x18\x0b \x03(\x0b\x32#.chromiumos.BuildReportBeta.Payload\x12<\n\tartifacts\x18\x07 \x03(\x0b\x32).chromiumos.BuildReportBeta.BuildArtifact\x1a\xf0\x01\n\x0b\x42uildStatus\x12=\n\x05value\x18\x01 \x01(\x0e\x32..chromiumos.BuildReportBeta.BuildStatus.Status\"\xa1\x01\n\x06Status\x12\r\n\tUNDEFINED\x10\x00\x12\x11\n\rKIND_TERMINAL\x10\x01\x12\x10\n\x0cKIND_RUNNING\x10\x02\x12\x0b\n\x07SUCCESS\x10\x64\x12\x0b\n\x07\x46\x41ILURE\x10\x65\x12\x11\n\rINFRA_FAILURE\x10\x66\x12\x0c\n\x08WATCHDOG\x10g\x12\x0c\n\x08\x43\x41NCELED\x10h\x12\x0c\n\x07RUNNING\x10\xc8\x01\x12\x0c\n\x07WAITING\x10\xc9\x01\x1a\xb7\x0b\n\x0b\x42uildConfig\x12>\n\x06\x62ranch\x18\x01 \x01(\x0b\x32..chromiumos.BuildReportBeta.BuildConfig.Branch\x12P\n\x18\x61ndroid_container_branch\x18\x02 \x01(\x0b\x32..chromiumos.BuildReportBeta.BuildConfig.Branch\x12>\n\x06target\x18\x03 \x01(\x0b\x32..chromiumos.BuildReportBeta.BuildConfig.Target\x12P\n\x18\x61ndroid_container_target\x18\x04 \x01(\x0b\x32..chromiumos.BuildReportBeta.BuildConfig.Target\x12@\n\x07release\x18\x05 \x01(\x0b\x32/.chromiumos.BuildReportBeta.BuildConfig.Release\x12\x41\n\x08versions\x18\x06 \x03(\x0b\x32/.chromiumos.BuildReportBeta.BuildConfig.Version\x12\x13\n\x0b\x61rc_use_set\x18\x07 \x01(\x08\x12=\n\x06models\x18\x08 \x03(\x0b\x32-.chromiumos.BuildReportBeta.BuildConfig.Model\x1a\xa3\x03\n\x05Model\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x17\n\x0f\x66irmware_key_id\x18\x02 \x01(\t\x12L\n\x08versions\x18\x03 \x03(\x0b\x32:.chromiumos.BuildReportBeta.BuildConfig.Model.ModelVersion\x1ak\n\x0cModelVersion\x12L\n\x04kind\x18\x01 \x01(\x0e\x32>.chromiumos.BuildReportBeta.BuildConfig.Model.ModelVersionKind\x12\r\n\x05value\x18\x02 \x01(\t\"\xb7\x01\n\x10ModelVersionKind\x12 \n\x1cMODEL_VERSION_KIND_UNDEFINED\x10\x00\x12\"\n\x1eMODEL_VERSION_KIND_EC_FIRMWARE\x10\x01\x12-\n)MODEL_VERSION_KIND_MAIN_READONLY_FIRMWARE\x10\x02\x12.\n*MODEL_VERSION_KIND_MAIN_READWRITE_FIRMWARE\x10\x03\x1a\x30\n\x07Release\x12%\n\x08\x63hannels\x18\x01 \x03(\x0e\x32\x13.chromiumos.Channel\x1a\x16\n\x06\x42ranch\x12\x0c\n\x04name\x18\x01 \x01(\t\x1a[\n\x07Version\x12\x41\n\x04kind\x18\x01 \x01(\x0e\x32\x33.chromiumos.BuildReportBeta.BuildConfig.VersionKind\x12\r\n\x05value\x18\x02 \x01(\t\x1a\x16\n\x06Target\x12\x0c\n\x04name\x18\x01 \x01(\t\"\xc5\x02\n\x0bVersionKind\x12\x1a\n\x16VERSION_KIND_UNDEFINED\x10\x00\x12\x1b\n\x17VERSION_KIND_ASH_CHROME\x10\x01\x12\x17\n\x13VERSION_KIND_CHROME\x10\x02\x12\x14\n\x10VERSION_KIND_ARC\x10\x03\x12\x19\n\x15VERSION_KIND_PLATFORM\x10\x04\x12\x1a\n\x16VERSION_KIND_MILESTONE\x10\x05\x12\"\n\x1eVERSION_KIND_ANDROID_CONTAINER\x10\x06\x12\x1c\n\x18VERSION_KIND_EC_FIRMWARE\x10\x07\x12\x1c\n\x18VERSION_KIND_FINGERPRINT\x10\x08\x12\x17\n\x13VERSION_KIND_KERNEL\x10\t\x12\x1e\n\x1aVERSION_KIND_MAIN_FIRMWARE\x10\n\x1a\xef\x04\n\rBuildArtifact\x12<\n\x04type\x18\x01 \x01(\x0e\x32..chromiumos.BuildReportBeta.BuildArtifact.Type\x12:\n\x03uri\x18\x02 \x01(\x0b\x32-.chromiumos.BuildReportBeta.BuildArtifact.URI\x12\x0e\n\x06sha256\x18\x03 \x01(\t\x12+\n\x07\x63reated\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x1a\x1b\n\x03URI\x12\r\n\x03gcs\x18\x01 \x01(\tH\x00\x42\x05\n\x03uri\"\x89\x03\n\x04Type\x12\r\n\tUNDEFINED\x10\x00\x12\x0f\n\x0bIMAGE_TYPES\x10\x01\x12\x12\n\x0e\x46IRMWARE_TYPES\x10\x02\x12\x0e\n\nAFDO_TYPES\x10\x03\x12\x11\n\rPAYLOAD_TYPES\x10\x04\x12\x11\n\rRELEASE_IMAGE\x10\x64\x12\x12\n\x0eRECOVERY_IMAGE\x10\x65\x12\r\n\tDLC_IMAGE\x10\x66\x12\x16\n\x12\x44\x45\x42UG_SYMBOL_IMAGE\x10g\x12\x10\n\x0cHWQUAL_IMAGE\x10h\x12\x0e\n\nTEST_IMAGE\x10i\x12\x15\n\x10\x46IRMWARE_TARBALL\x10\xc8\x01\x12\x1a\n\x15\x46IRMWARE_TARBALL_INFO\x10\xc9\x01\x12\x12\n\rFIRMWARE_LCOV\x10\xca\x01\x12\x13\n\x0e\x41\x46\x44O_ORDERFILE\x10\xac\x02\x12\x13\n\x0e\x41\x46\x44O_BENCHMARK\x10\xad\x02\x12\x10\n\x0b\x41\x46\x44O_KERNEL\x10\xae\x02\x12\x10\n\x0b\x41\x46\x44O_CHROME\x10\xaf\x02\x12\x11\n\x0cPAYLOAD_FULL\x10\x90\x03\x12\x12\n\rPAYLOAD_DELTA\x10\x91\x03\x1a\xc6\x06\n\x0bStepDetails\x12\x41\n\x07\x63urrent\x18\x01 \x01(\x0e\x32\x30.chromiumos.BuildReportBeta.StepDetails.StepName\x12?\n\x04info\x18\x02 \x03(\x0b\x32\x31.chromiumos.BuildReportBeta.StepDetails.InfoEntry\x1a\x81\x01\n\x08StepInfo\x12\r\n\x05order\x18\x01 \x01(\x05\x12>\n\x06status\x18\x02 \x01(\x0e\x32..chromiumos.BuildReportBeta.StepDetails.Status\x12&\n\x07runtime\x18\x03 \x01(\x0b\x32\x15.chromiumos.Timeframe\x1a]\n\tInfoEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12?\n\x05value\x18\x02 \x01(\x0b\x32\x30.chromiumos.BuildReportBeta.StepDetails.StepInfo:\x02\x38\x01\"\xc9\x01\n\x06Status\x12\x19\n\x15STEP_STATUS_UNDEFINED\x10\x00\x12\x11\n\rKIND_TERMINAL\x10\x01\x12\x10\n\x0cKIND_RUNNING\x10\x02\x12\x12\n\x0eSTATUS_SUCCESS\x10\x64\x12\x12\n\x0eSTATUS_FAILURE\x10\x65\x12\x18\n\x14STATUS_INFRA_FAILURE\x10\x66\x12\x13\n\x0fSTATUS_WATCHDOG\x10g\x12\x13\n\x0fSTATUS_CANCELED\x10h\x12\x13\n\x0eSTATUS_RUNNING\x10\xc8\x01\"\x83\x02\n\x08StepName\x12\x12\n\x0eSTEP_UNDEFINED\x10\x00\x12\x10\n\x0cSTEP_OVERALL\x10\x64\x12\x0e\n\tSTEP_SYNC\x10\xc8\x01\x12\x15\n\x10STEP_SYNC_CHROME\x10\xc9\x01\x12\r\n\x08STEP_SDK\x10\xac\x02\x12\x12\n\rSTEP_SDK_INIT\x10\xad\x02\x12\x14\n\x0fSTEP_SDK_UPDATE\x10\xae\x02\x12\x0f\n\nSTEP_BUILD\x10\x90\x03\x12\x17\n\x12STEP_BUILD_SYSROOT\x10\x91\x03\x12\x18\n\x13STEP_BUILD_PACKAGES\x10\x92\x03\x12\x17\n\x12STEP_DEBUG_SYMBOLS\x10\xf4\x03\x12\x14\n\x0fSTEP_UNIT_TESTS\x10\xf5\x03\x1a\x98\x08\n\x13SignedBuildMetadata\x12M\n\x06status\x18\x01 \x01(\x0e\x32=.chromiumos.BuildReportBeta.SignedBuildMetadata.SigningStatus\x12\r\n\x05\x62oard\x18\x02 \x01(\t\x12#\n\x04type\x18\x03 \x01(\x0e\x32\x15.chromiumos.ImageType\x12$\n\x07\x63hannel\x18\x04 \x01(\x0e\x32\x13.chromiumos.Channel\x12\x0e\n\x06keyset\x18\x05 \x01(\t\x12\x14\n\x0ckeyset_is_mp\x18\x06 \x01(\x08\x12M\n\x05\x66iles\x18\x07 \x03(\x0b\x32>.chromiumos.BuildReportBeta.SignedBuildMetadata.FileWithHashes\x12I\n\x08versions\x18\x08 \x03(\x0b\x32\x37.chromiumos.BuildReportBeta.SignedBuildMetadata.Version\x1a[\n\x0e\x46ileWithHashes\x12\x10\n\x08\x66ilename\x18\x01 \x01(\t\x12\x0b\n\x03md5\x18\x02 \x01(\t\x12\x0c\n\x04sha1\x18\x03 \x01(\t\x12\x0e\n\x06sha256\x18\x04 \x01(\t\x12\x0c\n\x04size\x18\x05 \x01(\x03\x1a\x63\n\x07Version\x12I\n\x04kind\x18\x01 \x01(\x0e\x32;.chromiumos.BuildReportBeta.SignedBuildMetadata.VersionKind\x12\r\n\x05value\x18\x02 \x01(\t\"\xe0\x01\n\x0bVersionKind\x12\x1a\n\x16VERSION_KIND_UNDEFINED\x10\x00\x12\x19\n\x15VERSION_KIND_PLATFORM\x10\x01\x12\x1a\n\x16VERSION_KIND_MILESTONE\x10\x02\x12!\n\x1dVERSION_KIND_KEY_FIRMWARE_KEY\x10\x03\x12\x1d\n\x19VERSION_KIND_KEY_FIRMWARE\x10\x04\x12\x1f\n\x1bVERSION_KIND_KEY_KERNEL_KEY\x10\x05\x12\x1b\n\x17VERSION_KIND_KEY_KERNEL\x10\x06\"\xf2\x01\n\rSigningStatus\x12\x1a\n\x16SIGNING_STATUS_UNKNOWN\x10\x00\x12\x1e\n\x1aSIGNING_STATUS_DOWNLOADING\x10\x01\x12\x1a\n\x16SIGNING_STATUS_SIGNING\x10\x02\x12\x1c\n\x18SIGNING_STATUS_UPLOADING\x10\x03\x12\x1b\n\x17SIGNING_STATUS_FINISHED\x10\x04\x12\x18\n\x14SIGNING_STATUS_RETRY\x10\x05\x12\x19\n\x15SIGNING_STATUS_PASSED\x10\x06\x12\x19\n\x15SIGNING_STATUS_FAILED\x10\x07\x1a\xb4\x03\n\x07Payload\x12:\n\x07payload\x18\x01 \x01(\x0b\x32).chromiumos.BuildReportBeta.BuildArtifact\x12\x45\n\x0cpayload_type\x18\x02 \x01(\x0e\x32/.chromiumos.BuildReportBeta.Payload.PayloadType\x12\r\n\x05\x62oard\x18\x03 \x01(\t\x12$\n\x07\x63hannel\x18\x04 \x01(\x0e\x32\x13.chromiumos.Channel\x12\r\n\x05\x61ppid\x18\x05 \x01(\t\x12\x1a\n\x12metadata_signature\x18\x06 \x01(\t\x12\x15\n\rmetadata_size\x18\x07 \x01(\x03\x12\x16\n\x0esource_version\x18\x08 \x01(\t\x12\x16\n\x0etarget_version\x18\t \x01(\t\x12\x0c\n\x04size\x18\n \x01(\x03\"q\n\x0bPayloadType\x12\x18\n\x14PAYLOAD_TYPE_UNKNOWN\x10\x00\x12\x19\n\x15PAYLOAD_TYPE_STANDARD\x10\x01\x12\x17\n\x13PAYLOAD_TYPE_MINIOS\x10\x02\x12\x14\n\x10PAYLOAD_TYPE_DLC\x10\x03\"n\n\tBuildType\x12\x18\n\x14\x42UILD_TYPE_UNDEFINED\x10\x00\x12\x16\n\x12\x42UILD_TYPE_RELEASE\x10\x01\x12\x17\n\x13\x42UILD_TYPE_FIRMWARE\x10\x02\x12\x16\n\x12\x42UILD_TYPE_FACTORY\x10\x03\x42\x04\n\x02id\"E\n\x0f\x42uildReportList\x12\x32\n\rbuild_reports\x18\x01 \x03(\x0b\x32\x1b.chromiumos.BuildReportBetaBY\n!com.google.chrome.crosinfra.protoZ4go.chromium.org/chromiumos/infra/proto/go/chromiumosb\x06proto3'
   ,
   dependencies=[chromiumos_dot_common__pb2.DESCRIPTOR,google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,])
 
@@ -87,11 +87,116 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=611,
-  serialized_end=772,
+  serialized_start=872,
+  serialized_end=1033,
 )
 _sym_db.RegisterEnumDescriptor(_BUILDREPORTBETA_BUILDSTATUS_STATUS)
 
+_BUILDREPORTBETA_BUILDCONFIG_MODEL_MODELVERSIONKIND = _descriptor.EnumDescriptor(
+  name='ModelVersionKind',
+  full_name='chromiumos.BuildReportBeta.BuildConfig.Model.ModelVersionKind',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='MODEL_VERSION_KIND_UNDEFINED', index=0, number=0,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='MODEL_VERSION_KIND_EC_FIRMWARE', index=1, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='MODEL_VERSION_KIND_MAIN_READONLY_FIRMWARE', index=2, number=2,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='MODEL_VERSION_KIND_MAIN_READWRITE_FIRMWARE', index=3, number=3,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=1797,
+  serialized_end=1980,
+)
+_sym_db.RegisterEnumDescriptor(_BUILDREPORTBETA_BUILDCONFIG_MODEL_MODELVERSIONKIND)
+
+_BUILDREPORTBETA_BUILDCONFIG_VERSIONKIND = _descriptor.EnumDescriptor(
+  name='VersionKind',
+  full_name='chromiumos.BuildReportBeta.BuildConfig.VersionKind',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_UNDEFINED', index=0, number=0,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_ASH_CHROME', index=1, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_CHROME', index=2, number=2,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_ARC', index=3, number=3,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_PLATFORM', index=4, number=4,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_MILESTONE', index=5, number=5,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_ANDROID_CONTAINER', index=6, number=6,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_EC_FIRMWARE', index=7, number=7,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_FINGERPRINT', index=8, number=8,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_KERNEL', index=9, number=9,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_MAIN_FIRMWARE', index=10, number=10,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=2174,
+  serialized_end=2499,
+)
+_sym_db.RegisterEnumDescriptor(_BUILDREPORTBETA_BUILDCONFIG_VERSIONKIND)
+
 _BUILDREPORTBETA_BUILDARTIFACT_TYPE = _descriptor.EnumDescriptor(
   name='Type',
   full_name='chromiumos.BuildReportBeta.BuildArtifact.Type',
@@ -120,75 +225,90 @@
       type=None,
       create_key=_descriptor._internal_create_key),
     _descriptor.EnumValueDescriptor(
-      name='RELEASE_IMAGE', index=4, number=100,
+      name='PAYLOAD_TYPES', index=4, number=4,
       serialized_options=None,
       type=None,
       create_key=_descriptor._internal_create_key),
     _descriptor.EnumValueDescriptor(
-      name='RECOVERY_IMAGE', index=5, number=101,
+      name='RELEASE_IMAGE', index=5, number=100,
       serialized_options=None,
       type=None,
       create_key=_descriptor._internal_create_key),
     _descriptor.EnumValueDescriptor(
-      name='DLC_IMAGE', index=6, number=102,
+      name='RECOVERY_IMAGE', index=6, number=101,
       serialized_options=None,
       type=None,
       create_key=_descriptor._internal_create_key),
     _descriptor.EnumValueDescriptor(
-      name='DEBUG_SYMBOL_IMAGE', index=7, number=103,
+      name='DLC_IMAGE', index=7, number=102,
       serialized_options=None,
       type=None,
       create_key=_descriptor._internal_create_key),
     _descriptor.EnumValueDescriptor(
-      name='HWQUAL_IMAGE', index=8, number=104,
+      name='DEBUG_SYMBOL_IMAGE', index=8, number=103,
       serialized_options=None,
       type=None,
       create_key=_descriptor._internal_create_key),
     _descriptor.EnumValueDescriptor(
-      name='TEST_IMAGE', index=9, number=105,
+      name='HWQUAL_IMAGE', index=9, number=104,
       serialized_options=None,
       type=None,
       create_key=_descriptor._internal_create_key),
     _descriptor.EnumValueDescriptor(
-      name='FIRMWARE_TARBALL', index=10, number=200,
+      name='TEST_IMAGE', index=10, number=105,
       serialized_options=None,
       type=None,
       create_key=_descriptor._internal_create_key),
     _descriptor.EnumValueDescriptor(
-      name='FIRMWARE_TARBALL_INFO', index=11, number=201,
+      name='FIRMWARE_TARBALL', index=11, number=200,
       serialized_options=None,
       type=None,
       create_key=_descriptor._internal_create_key),
     _descriptor.EnumValueDescriptor(
-      name='FIRMWARE_LCOV', index=12, number=202,
+      name='FIRMWARE_TARBALL_INFO', index=12, number=201,
       serialized_options=None,
       type=None,
       create_key=_descriptor._internal_create_key),
     _descriptor.EnumValueDescriptor(
-      name='AFDO_ORDERFILE', index=13, number=300,
+      name='FIRMWARE_LCOV', index=13, number=202,
       serialized_options=None,
       type=None,
       create_key=_descriptor._internal_create_key),
     _descriptor.EnumValueDescriptor(
-      name='AFDO_BENCHMARK', index=14, number=301,
+      name='AFDO_ORDERFILE', index=14, number=300,
       serialized_options=None,
       type=None,
       create_key=_descriptor._internal_create_key),
     _descriptor.EnumValueDescriptor(
-      name='AFDO_KERNEL', index=15, number=302,
+      name='AFDO_BENCHMARK', index=15, number=301,
       serialized_options=None,
       type=None,
       create_key=_descriptor._internal_create_key),
     _descriptor.EnumValueDescriptor(
-      name='AFDO_CHROME', index=16, number=303,
+      name='AFDO_KERNEL', index=16, number=302,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='AFDO_CHROME', index=17, number=303,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='PAYLOAD_FULL', index=18, number=400,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='PAYLOAD_DELTA', index=19, number=401,
       serialized_options=None,
       type=None,
       create_key=_descriptor._internal_create_key),
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1345,
-  serialized_end=1680,
+  serialized_start=2732,
+  serialized_end=3125,
 )
 _sym_db.RegisterEnumDescriptor(_BUILDREPORTBETA_BUILDARTIFACT_TYPE)
 
@@ -247,8 +367,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2058,
-  serialized_end=2259,
+  serialized_start=3503,
+  serialized_end=3704,
 )
 _sym_db.RegisterEnumDescriptor(_BUILDREPORTBETA_STEPDETAILS_STATUS)
 
@@ -309,14 +429,164 @@
       serialized_options=None,
       type=None,
       create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='STEP_DEBUG_SYMBOLS', index=10, number=500,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='STEP_UNIT_TESTS', index=11, number=501,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2262,
-  serialized_end=2474,
+  serialized_start=3707,
+  serialized_end=3966,
 )
 _sym_db.RegisterEnumDescriptor(_BUILDREPORTBETA_STEPDETAILS_STEPNAME)
 
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA_VERSIONKIND = _descriptor.EnumDescriptor(
+  name='VersionKind',
+  full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.VersionKind',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_UNDEFINED', index=0, number=0,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_PLATFORM', index=1, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_MILESTONE', index=2, number=2,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_KEY_FIRMWARE_KEY', index=3, number=3,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_KEY_FIRMWARE', index=4, number=4,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_KEY_KERNEL_KEY', index=5, number=5,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_KEY_KERNEL', index=6, number=6,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=4548,
+  serialized_end=4772,
+)
+_sym_db.RegisterEnumDescriptor(_BUILDREPORTBETA_SIGNEDBUILDMETADATA_VERSIONKIND)
+
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA_SIGNINGSTATUS = _descriptor.EnumDescriptor(
+  name='SigningStatus',
+  full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.SigningStatus',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='SIGNING_STATUS_UNKNOWN', index=0, number=0,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='SIGNING_STATUS_DOWNLOADING', index=1, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='SIGNING_STATUS_SIGNING', index=2, number=2,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='SIGNING_STATUS_UPLOADING', index=3, number=3,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='SIGNING_STATUS_FINISHED', index=4, number=4,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='SIGNING_STATUS_RETRY', index=5, number=5,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='SIGNING_STATUS_PASSED', index=6, number=6,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='SIGNING_STATUS_FAILED', index=7, number=7,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=4775,
+  serialized_end=5017,
+)
+_sym_db.RegisterEnumDescriptor(_BUILDREPORTBETA_SIGNEDBUILDMETADATA_SIGNINGSTATUS)
+
+_BUILDREPORTBETA_PAYLOAD_PAYLOADTYPE = _descriptor.EnumDescriptor(
+  name='PayloadType',
+  full_name='chromiumos.BuildReportBeta.Payload.PayloadType',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='PAYLOAD_TYPE_UNKNOWN', index=0, number=0,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='PAYLOAD_TYPE_STANDARD', index=1, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='PAYLOAD_TYPE_MINIOS', index=2, number=2,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='PAYLOAD_TYPE_DLC', index=3, number=3,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=5343,
+  serialized_end=5456,
+)
+_sym_db.RegisterEnumDescriptor(_BUILDREPORTBETA_PAYLOAD_PAYLOADTYPE)
+
 _BUILDREPORTBETA_BUILDTYPE = _descriptor.EnumDescriptor(
   name='BuildType',
   full_name='chromiumos.BuildReportBeta.BuildType',
@@ -347,8 +617,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2476,
-  serialized_end=2586,
+  serialized_start=5458,
+  serialized_end=5568,
 )
 _sym_db.RegisterEnumDescriptor(_BUILDREPORTBETA_BUILDTYPE)
 
@@ -392,6 +662,43 @@
 )
 
 
+_BUILDID = _descriptor.Descriptor(
+  name='BuildId',
+  full_name='chromiumos.BuildId',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='buildbucket_id', full_name='chromiumos.BuildId.buildbucket_id', index=0,
+      number=1, type=3, cpp_type=2, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+    _descriptor.OneofDescriptor(
+      name='id', full_name='chromiumos.BuildId.id',
+      index=0, containing_type=None,
+      create_key=_descriptor._internal_create_key,
+    fields=[]),
+  ],
+  serialized_start=200,
+  serialized_end=241,
+)
+
+
 _BUILDREPORTBETA_BUILDSTATUS = _descriptor.Descriptor(
   name='BuildStatus',
   full_name='chromiumos.BuildReportBeta.BuildStatus',
@@ -420,8 +727,46 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=532,
-  serialized_end=772,
+  serialized_start=793,
+  serialized_end=1033,
+)
+
+_BUILDREPORTBETA_BUILDCONFIG_MODEL_MODELVERSION = _descriptor.Descriptor(
+  name='ModelVersion',
+  full_name='chromiumos.BuildReportBeta.BuildConfig.Model.ModelVersion',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='kind', full_name='chromiumos.BuildReportBeta.BuildConfig.Model.ModelVersion.kind', index=0,
+      number=1, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='chromiumos.BuildReportBeta.BuildConfig.Model.ModelVersion.value', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1687,
+  serialized_end=1794,
 )
 
 _BUILDREPORTBETA_BUILDCONFIG_MODEL = _descriptor.Descriptor(
@@ -439,11 +784,26 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='firmware_key_id', full_name='chromiumos.BuildReportBeta.BuildConfig.Model.firmware_key_id', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='versions', full_name='chromiumos.BuildReportBeta.BuildConfig.Model.versions', index=2,
+      number=3, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
-  nested_types=[],
+  nested_types=[_BUILDREPORTBETA_BUILDCONFIG_MODEL_MODELVERSION, ],
   enum_types=[
+    _BUILDREPORTBETA_BUILDCONFIG_MODEL_MODELVERSIONKIND,
   ],
   serialized_options=None,
   is_extendable=False,
@@ -451,8 +811,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=983,
-  serialized_end=1004,
+  serialized_start=1561,
+  serialized_end=1980,
 )
 
 _BUILDREPORTBETA_BUILDCONFIG_RELEASE = _descriptor.Descriptor(
@@ -464,22 +824,8 @@
   create_key=_descriptor._internal_create_key,
   fields=[
     _descriptor.FieldDescriptor(
-      name='milestone', full_name='chromiumos.BuildReportBeta.BuildConfig.Release.milestone', index=0,
-      number=1, type=5, cpp_type=1, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='build', full_name='chromiumos.BuildReportBeta.BuildConfig.Release.build', index=1,
-      number=2, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=b"".decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='channels', full_name='chromiumos.BuildReportBeta.BuildConfig.Release.channels', index=2,
-      number=3, type=14, cpp_type=8, label=3,
+      name='channels', full_name='chromiumos.BuildReportBeta.BuildConfig.Release.channels', index=0,
+      number=1, type=14, cpp_type=8, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
@@ -496,8 +842,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1006,
-  serialized_end=1088,
+  serialized_start=1982,
+  serialized_end=2030,
 )
 
 _BUILDREPORTBETA_BUILDCONFIG_BRANCH = _descriptor.Descriptor(
@@ -527,8 +873,77 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1090,
-  serialized_end=1112,
+  serialized_start=2032,
+  serialized_end=2054,
+)
+
+_BUILDREPORTBETA_BUILDCONFIG_VERSION = _descriptor.Descriptor(
+  name='Version',
+  full_name='chromiumos.BuildReportBeta.BuildConfig.Version',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='kind', full_name='chromiumos.BuildReportBeta.BuildConfig.Version.kind', index=0,
+      number=1, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='chromiumos.BuildReportBeta.BuildConfig.Version.value', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2056,
+  serialized_end=2147,
+)
+
+_BUILDREPORTBETA_BUILDCONFIG_TARGET = _descriptor.Descriptor(
+  name='Target',
+  full_name='chromiumos.BuildReportBeta.BuildConfig.Target',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='name', full_name='chromiumos.BuildReportBeta.BuildConfig.Target.name', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2149,
+  serialized_end=2171,
 )
 
 _BUILDREPORTBETA_BUILDCONFIG = _descriptor.Descriptor(
@@ -547,15 +962,50 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='release', full_name='chromiumos.BuildReportBeta.BuildConfig.release', index=1,
+      name='android_container_branch', full_name='chromiumos.BuildReportBeta.BuildConfig.android_container_branch', index=1,
       number=2, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='models', full_name='chromiumos.BuildReportBeta.BuildConfig.models', index=2,
-      number=3, type=11, cpp_type=10, label=3,
+      name='target', full_name='chromiumos.BuildReportBeta.BuildConfig.target', index=2,
+      number=3, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='android_container_target', full_name='chromiumos.BuildReportBeta.BuildConfig.android_container_target', index=3,
+      number=4, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='release', full_name='chromiumos.BuildReportBeta.BuildConfig.release', index=4,
+      number=5, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='versions', full_name='chromiumos.BuildReportBeta.BuildConfig.versions', index=5,
+      number=6, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='arc_use_set', full_name='chromiumos.BuildReportBeta.BuildConfig.arc_use_set', index=6,
+      number=7, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='models', full_name='chromiumos.BuildReportBeta.BuildConfig.models', index=7,
+      number=8, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
@@ -563,8 +1013,9 @@
   ],
   extensions=[
   ],
-  nested_types=[_BUILDREPORTBETA_BUILDCONFIG_MODEL, _BUILDREPORTBETA_BUILDCONFIG_RELEASE, _BUILDREPORTBETA_BUILDCONFIG_BRANCH, ],
+  nested_types=[_BUILDREPORTBETA_BUILDCONFIG_MODEL, _BUILDREPORTBETA_BUILDCONFIG_RELEASE, _BUILDREPORTBETA_BUILDCONFIG_BRANCH, _BUILDREPORTBETA_BUILDCONFIG_VERSION, _BUILDREPORTBETA_BUILDCONFIG_TARGET, ],
   enum_types=[
+    _BUILDREPORTBETA_BUILDCONFIG_VERSIONKIND,
   ],
   serialized_options=None,
   is_extendable=False,
@@ -572,8 +1023,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=775,
-  serialized_end=1112,
+  serialized_start=1036,
+  serialized_end=2499,
 )
 
 _BUILDREPORTBETA_BUILDARTIFACT_URI = _descriptor.Descriptor(
@@ -608,8 +1059,8 @@
       create_key=_descriptor._internal_create_key,
     fields=[]),
   ],
-  serialized_start=1315,
-  serialized_end=1342,
+  serialized_start=2702,
+  serialized_end=2729,
 )
 
 _BUILDREPORTBETA_BUILDARTIFACT = _descriptor.Descriptor(
@@ -661,8 +1112,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1115,
-  serialized_end=1680,
+  serialized_start=2502,
+  serialized_end=3125,
 )
 
 _BUILDREPORTBETA_STEPDETAILS_STEPINFO = _descriptor.Descriptor(
@@ -706,8 +1157,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1831,
-  serialized_end=1960,
+  serialized_start=3276,
+  serialized_end=3405,
 )
 
 _BUILDREPORTBETA_STEPDETAILS_INFOENTRY = _descriptor.Descriptor(
@@ -744,8 +1195,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1962,
-  serialized_end=2055,
+  serialized_start=3407,
+  serialized_end=3500,
 )
 
 _BUILDREPORTBETA_STEPDETAILS = _descriptor.Descriptor(
@@ -784,8 +1235,282 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1683,
-  serialized_end=2474,
+  serialized_start=3128,
+  serialized_end=3966,
+)
+
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA_FILEWITHHASHES = _descriptor.Descriptor(
+  name='FileWithHashes',
+  full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.FileWithHashes',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='filename', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.FileWithHashes.filename', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='md5', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.FileWithHashes.md5', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='sha1', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.FileWithHashes.sha1', index=2,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='sha256', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.FileWithHashes.sha256', index=3,
+      number=4, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='size', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.FileWithHashes.size', index=4,
+      number=5, type=3, cpp_type=2, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=4353,
+  serialized_end=4444,
+)
+
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA_VERSION = _descriptor.Descriptor(
+  name='Version',
+  full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.Version',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='kind', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.Version.kind', index=0,
+      number=1, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.Version.value', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=4446,
+  serialized_end=4545,
+)
+
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA = _descriptor.Descriptor(
+  name='SignedBuildMetadata',
+  full_name='chromiumos.BuildReportBeta.SignedBuildMetadata',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='status', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.status', index=0,
+      number=1, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='board', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.board', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='type', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.type', index=2,
+      number=3, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='channel', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.channel', index=3,
+      number=4, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='keyset', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.keyset', index=4,
+      number=5, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='keyset_is_mp', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.keyset_is_mp', index=5,
+      number=6, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='files', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.files', index=6,
+      number=7, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='versions', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.versions', index=7,
+      number=8, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[_BUILDREPORTBETA_SIGNEDBUILDMETADATA_FILEWITHHASHES, _BUILDREPORTBETA_SIGNEDBUILDMETADATA_VERSION, ],
+  enum_types=[
+    _BUILDREPORTBETA_SIGNEDBUILDMETADATA_VERSIONKIND,
+    _BUILDREPORTBETA_SIGNEDBUILDMETADATA_SIGNINGSTATUS,
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=3969,
+  serialized_end=5017,
+)
+
+_BUILDREPORTBETA_PAYLOAD = _descriptor.Descriptor(
+  name='Payload',
+  full_name='chromiumos.BuildReportBeta.Payload',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='payload', full_name='chromiumos.BuildReportBeta.Payload.payload', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='payload_type', full_name='chromiumos.BuildReportBeta.Payload.payload_type', index=1,
+      number=2, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='board', full_name='chromiumos.BuildReportBeta.Payload.board', index=2,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='channel', full_name='chromiumos.BuildReportBeta.Payload.channel', index=3,
+      number=4, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='appid', full_name='chromiumos.BuildReportBeta.Payload.appid', index=4,
+      number=5, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='metadata_signature', full_name='chromiumos.BuildReportBeta.Payload.metadata_signature', index=5,
+      number=6, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='metadata_size', full_name='chromiumos.BuildReportBeta.Payload.metadata_size', index=6,
+      number=7, type=3, cpp_type=2, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='source_version', full_name='chromiumos.BuildReportBeta.Payload.source_version', index=7,
+      number=8, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='target_version', full_name='chromiumos.BuildReportBeta.Payload.target_version', index=8,
+      number=9, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='size', full_name='chromiumos.BuildReportBeta.Payload.size', index=9,
+      number=10, type=3, cpp_type=2, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+    _BUILDREPORTBETA_PAYLOAD_PAYLOADTYPE,
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=5020,
+  serialized_end=5456,
 )
 
 _BUILDREPORTBETA = _descriptor.Descriptor(
@@ -804,35 +1529,70 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='type', full_name='chromiumos.BuildReportBeta.type', index=1,
+      name='count', full_name='chromiumos.BuildReportBeta.count', index=1,
+      number=8, type=3, cpp_type=2, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='parent', full_name='chromiumos.BuildReportBeta.parent', index=2,
+      number=9, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='children', full_name='chromiumos.BuildReportBeta.children', index=3,
+      number=10, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='type', full_name='chromiumos.BuildReportBeta.type', index=4,
       number=2, type=14, cpp_type=8, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='status', full_name='chromiumos.BuildReportBeta.status', index=2,
+      name='status', full_name='chromiumos.BuildReportBeta.status', index=5,
       number=3, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='config', full_name='chromiumos.BuildReportBeta.config', index=3,
+      name='config', full_name='chromiumos.BuildReportBeta.config', index=6,
       number=4, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='steps', full_name='chromiumos.BuildReportBeta.steps', index=4,
+      name='steps', full_name='chromiumos.BuildReportBeta.steps', index=7,
       number=5, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='artifacts', full_name='chromiumos.BuildReportBeta.artifacts', index=5,
+      name='signed_builds', full_name='chromiumos.BuildReportBeta.signed_builds', index=8,
+      number=6, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='payloads', full_name='chromiumos.BuildReportBeta.payloads', index=9,
+      number=11, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='artifacts', full_name='chromiumos.BuildReportBeta.artifacts', index=10,
       number=7, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
@@ -841,7 +1601,7 @@
   ],
   extensions=[
   ],
-  nested_types=[_BUILDREPORTBETA_BUILDSTATUS, _BUILDREPORTBETA_BUILDCONFIG, _BUILDREPORTBETA_BUILDARTIFACT, _BUILDREPORTBETA_STEPDETAILS, ],
+  nested_types=[_BUILDREPORTBETA_BUILDSTATUS, _BUILDREPORTBETA_BUILDCONFIG, _BUILDREPORTBETA_BUILDARTIFACT, _BUILDREPORTBETA_STEPDETAILS, _BUILDREPORTBETA_SIGNEDBUILDMETADATA, _BUILDREPORTBETA_PAYLOAD, ],
   enum_types=[
     _BUILDREPORTBETA_BUILDTYPE,
   ],
@@ -856,23 +1616,70 @@
       create_key=_descriptor._internal_create_key,
     fields=[]),
   ],
-  serialized_start=201,
-  serialized_end=2592,
+  serialized_start=244,
+  serialized_end=5574,
+)
+
+
+_BUILDREPORTLIST = _descriptor.Descriptor(
+  name='BuildReportList',
+  full_name='chromiumos.BuildReportList',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='build_reports', full_name='chromiumos.BuildReportList.build_reports', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=5576,
+  serialized_end=5645,
 )
 
 _TIMEFRAME.fields_by_name['begin'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP
 _TIMEFRAME.fields_by_name['end'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP
+_BUILDID.oneofs_by_name['id'].fields.append(
+  _BUILDID.fields_by_name['buildbucket_id'])
+_BUILDID.fields_by_name['buildbucket_id'].containing_oneof = _BUILDID.oneofs_by_name['id']
 _BUILDREPORTBETA_BUILDSTATUS.fields_by_name['value'].enum_type = _BUILDREPORTBETA_BUILDSTATUS_STATUS
 _BUILDREPORTBETA_BUILDSTATUS.containing_type = _BUILDREPORTBETA
 _BUILDREPORTBETA_BUILDSTATUS_STATUS.containing_type = _BUILDREPORTBETA_BUILDSTATUS
+_BUILDREPORTBETA_BUILDCONFIG_MODEL_MODELVERSION.fields_by_name['kind'].enum_type = _BUILDREPORTBETA_BUILDCONFIG_MODEL_MODELVERSIONKIND
+_BUILDREPORTBETA_BUILDCONFIG_MODEL_MODELVERSION.containing_type = _BUILDREPORTBETA_BUILDCONFIG_MODEL
+_BUILDREPORTBETA_BUILDCONFIG_MODEL.fields_by_name['versions'].message_type = _BUILDREPORTBETA_BUILDCONFIG_MODEL_MODELVERSION
 _BUILDREPORTBETA_BUILDCONFIG_MODEL.containing_type = _BUILDREPORTBETA_BUILDCONFIG
+_BUILDREPORTBETA_BUILDCONFIG_MODEL_MODELVERSIONKIND.containing_type = _BUILDREPORTBETA_BUILDCONFIG_MODEL
 _BUILDREPORTBETA_BUILDCONFIG_RELEASE.fields_by_name['channels'].enum_type = chromiumos_dot_common__pb2._CHANNEL
 _BUILDREPORTBETA_BUILDCONFIG_RELEASE.containing_type = _BUILDREPORTBETA_BUILDCONFIG
 _BUILDREPORTBETA_BUILDCONFIG_BRANCH.containing_type = _BUILDREPORTBETA_BUILDCONFIG
+_BUILDREPORTBETA_BUILDCONFIG_VERSION.fields_by_name['kind'].enum_type = _BUILDREPORTBETA_BUILDCONFIG_VERSIONKIND
+_BUILDREPORTBETA_BUILDCONFIG_VERSION.containing_type = _BUILDREPORTBETA_BUILDCONFIG
+_BUILDREPORTBETA_BUILDCONFIG_TARGET.containing_type = _BUILDREPORTBETA_BUILDCONFIG
 _BUILDREPORTBETA_BUILDCONFIG.fields_by_name['branch'].message_type = _BUILDREPORTBETA_BUILDCONFIG_BRANCH
+_BUILDREPORTBETA_BUILDCONFIG.fields_by_name['android_container_branch'].message_type = _BUILDREPORTBETA_BUILDCONFIG_BRANCH
+_BUILDREPORTBETA_BUILDCONFIG.fields_by_name['target'].message_type = _BUILDREPORTBETA_BUILDCONFIG_TARGET
+_BUILDREPORTBETA_BUILDCONFIG.fields_by_name['android_container_target'].message_type = _BUILDREPORTBETA_BUILDCONFIG_TARGET
 _BUILDREPORTBETA_BUILDCONFIG.fields_by_name['release'].message_type = _BUILDREPORTBETA_BUILDCONFIG_RELEASE
+_BUILDREPORTBETA_BUILDCONFIG.fields_by_name['versions'].message_type = _BUILDREPORTBETA_BUILDCONFIG_VERSION
 _BUILDREPORTBETA_BUILDCONFIG.fields_by_name['models'].message_type = _BUILDREPORTBETA_BUILDCONFIG_MODEL
 _BUILDREPORTBETA_BUILDCONFIG.containing_type = _BUILDREPORTBETA
+_BUILDREPORTBETA_BUILDCONFIG_VERSIONKIND.containing_type = _BUILDREPORTBETA_BUILDCONFIG
 _BUILDREPORTBETA_BUILDARTIFACT_URI.containing_type = _BUILDREPORTBETA_BUILDARTIFACT
 _BUILDREPORTBETA_BUILDARTIFACT_URI.oneofs_by_name['uri'].fields.append(
   _BUILDREPORTBETA_BUILDARTIFACT_URI.fields_by_name['gcs'])
@@ -892,17 +1699,40 @@
 _BUILDREPORTBETA_STEPDETAILS.containing_type = _BUILDREPORTBETA
 _BUILDREPORTBETA_STEPDETAILS_STATUS.containing_type = _BUILDREPORTBETA_STEPDETAILS
 _BUILDREPORTBETA_STEPDETAILS_STEPNAME.containing_type = _BUILDREPORTBETA_STEPDETAILS
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA_FILEWITHHASHES.containing_type = _BUILDREPORTBETA_SIGNEDBUILDMETADATA
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA_VERSION.fields_by_name['kind'].enum_type = _BUILDREPORTBETA_SIGNEDBUILDMETADATA_VERSIONKIND
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA_VERSION.containing_type = _BUILDREPORTBETA_SIGNEDBUILDMETADATA
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA.fields_by_name['status'].enum_type = _BUILDREPORTBETA_SIGNEDBUILDMETADATA_SIGNINGSTATUS
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA.fields_by_name['type'].enum_type = chromiumos_dot_common__pb2._IMAGETYPE
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA.fields_by_name['channel'].enum_type = chromiumos_dot_common__pb2._CHANNEL
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA.fields_by_name['files'].message_type = _BUILDREPORTBETA_SIGNEDBUILDMETADATA_FILEWITHHASHES
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA.fields_by_name['versions'].message_type = _BUILDREPORTBETA_SIGNEDBUILDMETADATA_VERSION
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA.containing_type = _BUILDREPORTBETA
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA_VERSIONKIND.containing_type = _BUILDREPORTBETA_SIGNEDBUILDMETADATA
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA_SIGNINGSTATUS.containing_type = _BUILDREPORTBETA_SIGNEDBUILDMETADATA
+_BUILDREPORTBETA_PAYLOAD.fields_by_name['payload'].message_type = _BUILDREPORTBETA_BUILDARTIFACT
+_BUILDREPORTBETA_PAYLOAD.fields_by_name['payload_type'].enum_type = _BUILDREPORTBETA_PAYLOAD_PAYLOADTYPE
+_BUILDREPORTBETA_PAYLOAD.fields_by_name['channel'].enum_type = chromiumos_dot_common__pb2._CHANNEL
+_BUILDREPORTBETA_PAYLOAD.containing_type = _BUILDREPORTBETA
+_BUILDREPORTBETA_PAYLOAD_PAYLOADTYPE.containing_type = _BUILDREPORTBETA_PAYLOAD
+_BUILDREPORTBETA.fields_by_name['parent'].message_type = _BUILDID
+_BUILDREPORTBETA.fields_by_name['children'].message_type = _BUILDID
 _BUILDREPORTBETA.fields_by_name['type'].enum_type = _BUILDREPORTBETA_BUILDTYPE
 _BUILDREPORTBETA.fields_by_name['status'].message_type = _BUILDREPORTBETA_BUILDSTATUS
 _BUILDREPORTBETA.fields_by_name['config'].message_type = _BUILDREPORTBETA_BUILDCONFIG
 _BUILDREPORTBETA.fields_by_name['steps'].message_type = _BUILDREPORTBETA_STEPDETAILS
+_BUILDREPORTBETA.fields_by_name['signed_builds'].message_type = _BUILDREPORTBETA_SIGNEDBUILDMETADATA
+_BUILDREPORTBETA.fields_by_name['payloads'].message_type = _BUILDREPORTBETA_PAYLOAD
 _BUILDREPORTBETA.fields_by_name['artifacts'].message_type = _BUILDREPORTBETA_BUILDARTIFACT
 _BUILDREPORTBETA_BUILDTYPE.containing_type = _BUILDREPORTBETA
 _BUILDREPORTBETA.oneofs_by_name['id'].fields.append(
   _BUILDREPORTBETA.fields_by_name['buildbucket_id'])
 _BUILDREPORTBETA.fields_by_name['buildbucket_id'].containing_oneof = _BUILDREPORTBETA.oneofs_by_name['id']
+_BUILDREPORTLIST.fields_by_name['build_reports'].message_type = _BUILDREPORTBETA
 DESCRIPTOR.message_types_by_name['Timeframe'] = _TIMEFRAME
+DESCRIPTOR.message_types_by_name['BuildId'] = _BUILDID
 DESCRIPTOR.message_types_by_name['BuildReportBeta'] = _BUILDREPORTBETA
+DESCRIPTOR.message_types_by_name['BuildReportList'] = _BUILDREPORTLIST
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
 Timeframe = _reflection.GeneratedProtocolMessageType('Timeframe', (_message.Message,), {
@@ -912,6 +1742,13 @@
   })
 _sym_db.RegisterMessage(Timeframe)
 
+BuildId = _reflection.GeneratedProtocolMessageType('BuildId', (_message.Message,), {
+  'DESCRIPTOR' : _BUILDID,
+  '__module__' : 'chromiumos.build_report_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.BuildId)
+  })
+_sym_db.RegisterMessage(BuildId)
+
 BuildReportBeta = _reflection.GeneratedProtocolMessageType('BuildReportBeta', (_message.Message,), {
 
   'BuildStatus' : _reflection.GeneratedProtocolMessageType('BuildStatus', (_message.Message,), {
@@ -924,6 +1761,13 @@
   'BuildConfig' : _reflection.GeneratedProtocolMessageType('BuildConfig', (_message.Message,), {
 
     'Model' : _reflection.GeneratedProtocolMessageType('Model', (_message.Message,), {
+
+      'ModelVersion' : _reflection.GeneratedProtocolMessageType('ModelVersion', (_message.Message,), {
+        'DESCRIPTOR' : _BUILDREPORTBETA_BUILDCONFIG_MODEL_MODELVERSION,
+        '__module__' : 'chromiumos.build_report_pb2'
+        # @@protoc_insertion_point(class_scope:chromiumos.BuildReportBeta.BuildConfig.Model.ModelVersion)
+        })
+      ,
       'DESCRIPTOR' : _BUILDREPORTBETA_BUILDCONFIG_MODEL,
       '__module__' : 'chromiumos.build_report_pb2'
       # @@protoc_insertion_point(class_scope:chromiumos.BuildReportBeta.BuildConfig.Model)
@@ -943,6 +1787,20 @@
       # @@protoc_insertion_point(class_scope:chromiumos.BuildReportBeta.BuildConfig.Branch)
       })
     ,
+
+    'Version' : _reflection.GeneratedProtocolMessageType('Version', (_message.Message,), {
+      'DESCRIPTOR' : _BUILDREPORTBETA_BUILDCONFIG_VERSION,
+      '__module__' : 'chromiumos.build_report_pb2'
+      # @@protoc_insertion_point(class_scope:chromiumos.BuildReportBeta.BuildConfig.Version)
+      })
+    ,
+
+    'Target' : _reflection.GeneratedProtocolMessageType('Target', (_message.Message,), {
+      'DESCRIPTOR' : _BUILDREPORTBETA_BUILDCONFIG_TARGET,
+      '__module__' : 'chromiumos.build_report_pb2'
+      # @@protoc_insertion_point(class_scope:chromiumos.BuildReportBeta.BuildConfig.Target)
+      })
+    ,
     'DESCRIPTOR' : _BUILDREPORTBETA_BUILDCONFIG,
     '__module__' : 'chromiumos.build_report_pb2'
     # @@protoc_insertion_point(class_scope:chromiumos.BuildReportBeta.BuildConfig)
@@ -983,6 +1841,34 @@
     # @@protoc_insertion_point(class_scope:chromiumos.BuildReportBeta.StepDetails)
     })
   ,
+
+  'SignedBuildMetadata' : _reflection.GeneratedProtocolMessageType('SignedBuildMetadata', (_message.Message,), {
+
+    'FileWithHashes' : _reflection.GeneratedProtocolMessageType('FileWithHashes', (_message.Message,), {
+      'DESCRIPTOR' : _BUILDREPORTBETA_SIGNEDBUILDMETADATA_FILEWITHHASHES,
+      '__module__' : 'chromiumos.build_report_pb2'
+      # @@protoc_insertion_point(class_scope:chromiumos.BuildReportBeta.SignedBuildMetadata.FileWithHashes)
+      })
+    ,
+
+    'Version' : _reflection.GeneratedProtocolMessageType('Version', (_message.Message,), {
+      'DESCRIPTOR' : _BUILDREPORTBETA_SIGNEDBUILDMETADATA_VERSION,
+      '__module__' : 'chromiumos.build_report_pb2'
+      # @@protoc_insertion_point(class_scope:chromiumos.BuildReportBeta.SignedBuildMetadata.Version)
+      })
+    ,
+    'DESCRIPTOR' : _BUILDREPORTBETA_SIGNEDBUILDMETADATA,
+    '__module__' : 'chromiumos.build_report_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.BuildReportBeta.SignedBuildMetadata)
+    })
+  ,
+
+  'Payload' : _reflection.GeneratedProtocolMessageType('Payload', (_message.Message,), {
+    'DESCRIPTOR' : _BUILDREPORTBETA_PAYLOAD,
+    '__module__' : 'chromiumos.build_report_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.BuildReportBeta.Payload)
+    })
+  ,
   'DESCRIPTOR' : _BUILDREPORTBETA,
   '__module__' : 'chromiumos.build_report_pb2'
   # @@protoc_insertion_point(class_scope:chromiumos.BuildReportBeta)
@@ -991,13 +1877,27 @@
 _sym_db.RegisterMessage(BuildReportBeta.BuildStatus)
 _sym_db.RegisterMessage(BuildReportBeta.BuildConfig)
 _sym_db.RegisterMessage(BuildReportBeta.BuildConfig.Model)
+_sym_db.RegisterMessage(BuildReportBeta.BuildConfig.Model.ModelVersion)
 _sym_db.RegisterMessage(BuildReportBeta.BuildConfig.Release)
 _sym_db.RegisterMessage(BuildReportBeta.BuildConfig.Branch)
+_sym_db.RegisterMessage(BuildReportBeta.BuildConfig.Version)
+_sym_db.RegisterMessage(BuildReportBeta.BuildConfig.Target)
 _sym_db.RegisterMessage(BuildReportBeta.BuildArtifact)
 _sym_db.RegisterMessage(BuildReportBeta.BuildArtifact.URI)
 _sym_db.RegisterMessage(BuildReportBeta.StepDetails)
 _sym_db.RegisterMessage(BuildReportBeta.StepDetails.StepInfo)
 _sym_db.RegisterMessage(BuildReportBeta.StepDetails.InfoEntry)
+_sym_db.RegisterMessage(BuildReportBeta.SignedBuildMetadata)
+_sym_db.RegisterMessage(BuildReportBeta.SignedBuildMetadata.FileWithHashes)
+_sym_db.RegisterMessage(BuildReportBeta.SignedBuildMetadata.Version)
+_sym_db.RegisterMessage(BuildReportBeta.Payload)
+
+BuildReportList = _reflection.GeneratedProtocolMessageType('BuildReportList', (_message.Message,), {
+  'DESCRIPTOR' : _BUILDREPORTLIST,
+  '__module__' : 'chromiumos.build_report_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.BuildReportList)
+  })
+_sym_db.RegisterMessage(BuildReportList)
 
 
 DESCRIPTOR._options = None
diff --git a/api/gen/chromiumos/builder_config_pb2.py b/api/gen/chromiumos/builder_config_pb2.py
index 4a051f4..2bfefa6 100644
--- a/api/gen/chromiumos/builder_config_pb2.py
+++ b/api/gen/chromiumos/builder_config_pb2.py
@@ -22,7 +22,7 @@
   syntax='proto3',
   serialized_options=b'\n!com.google.chrome.crosinfra.protoZ4go.chromium.org/chromiumos/infra/proto/go/chromiumos',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n\x1f\x63hromiumos/builder_config.proto\x12\nchromiumos\x1a\x17\x63hromiumos/common.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/wrappers.proto\"\xa8*\n\rBuilderConfig\x12(\n\x02id\x18\x01 \x01(\x0b\x32\x1c.chromiumos.BuilderConfig.Id\x12\x32\n\x07general\x18\x02 \x01(\x0b\x32!.chromiumos.BuilderConfig.General\x12<\n\x0corchestrator\x18\x03 \x01(\x0b\x32&.chromiumos.BuilderConfig.Orchestrator\x12\x36\n\tartifacts\x18\x04 \x01(\x0b\x32#.chromiumos.BuilderConfig.Artifacts\x12\x30\n\x06\x63hrome\x18\x05 \x01(\x0b\x32 .chromiumos.BuilderConfig.Chrome\x12.\n\x05\x62uild\x18\x06 \x01(\x0b\x32\x1f.chromiumos.BuilderConfig.Build\x12\x37\n\nunit_tests\x18\x07 \x01(\x0b\x32#.chromiumos.BuilderConfig.UnitTests\x1a\xb6\x01\n\x02Id\x12\x0c\n\x04name\x18\x01 \x01(\t\x12/\n\x04type\x18\x03 \x01(\x0e\x32!.chromiumos.BuilderConfig.Id.Type\"c\n\x04Type\x12\x14\n\x10TYPE_UNSPECIFIED\x10\x00\x12\x06\n\x02\x43Q\x10\x01\x12\x0e\n\nPOSTSUBMIT\x10\x02\x12\r\n\tTOOLCHAIN\x10\x03\x12\x11\n\rINFORMATIONAL\x10\x04\x12\x0b\n\x07RELEASE\x10\x05J\x04\x08\x02\x10\x03R\x06\x62ranch\x1a\xd6\x05\n\x07General\x12,\n\x08\x63ritical\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.BoolValue\x12\x42\n\x0b\x65nvironment\x18\x02 \x01(\x0e\x32-.chromiumos.BuilderConfig.General.Environment\x12;\n\x08run_when\x18\x03 \x01(\x0b\x32).chromiumos.BuilderConfig.General.RunWhen\x12\x31\n\rbroken_before\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x19\n\x11sdk_cache_version\x18\x05 \x01(\x05\x12\x10\n\x08unibuild\x18\x06 \x01(\x08\x12<\n\x08manifest\x18\x07 \x01(\x0e\x32*.chromiumos.BuilderConfig.General.Manifest\x12\x31\n\x11\x66irmware_location\x18\x08 \x01(\x0e\x32\x16.chromiumos.FwLocation\x1a\xc2\x01\n\x07RunWhen\x12<\n\x04mode\x18\x01 \x01(\x0e\x32..chromiumos.BuilderConfig.General.RunWhen.Mode\x12\x15\n\rfile_patterns\x18\x02 \x03(\t\"b\n\x04Mode\x12\x14\n\x10MODE_UNSPECIFIED\x10\x00\x12\x0e\n\nALWAYS_RUN\x10\x01\x12\x1a\n\x16ONLY_RUN_ON_FILE_MATCH\x10\x02\x12\x18\n\x14NO_RUN_ON_FILE_MATCH\x10\x03\"G\n\x0b\x45nvironment\x12\x1b\n\x17\x45NVIRONMENT_UNSPECIFIED\x10\x00\x12\x0e\n\nPRODUCTION\x10\x01\x12\x0b\n\x07STAGING\x10\x02\"=\n\x08Manifest\x12\x18\n\x14MANIFEST_UNSPECIFIED\x10\x00\x12\n\n\x06PUBLIC\x10\x01\x12\x0b\n\x07PRIVATE\x10\x02\x1a\xc2\x04\n\x0cOrchestrator\x12\x45\n\x0b\x63hild_specs\x18\x05 \x03(\x0b\x32\x30.chromiumos.BuilderConfig.Orchestrator.ChildSpec\x12\x31\n\x0egitiles_commit\x18\x02 \x01(\x0b\x32\x19.chromiumos.GitilesCommit\x12\x30\n\x0egerrit_changes\x18\x03 \x03(\x0b\x32\x18.chromiumos.GerritChange\x12[\n\x16\x66ollow_on_orchestrator\x18\x04 \x01(\x0b\x32;.chromiumos.BuilderConfig.Orchestrator.FollowOnOrchestrator\x1a\xe2\x01\n\tChildSpec\x12\x0c\n\x04name\x18\x01 \x01(\t\x12Z\n\x10\x63ollect_handling\x18\x02 \x01(\x0e\x32@.chromiumos.BuilderConfig.Orchestrator.ChildSpec.CollectHandling\"k\n\x0f\x43ollectHandling\x12 \n\x1c\x43OLLECT_HANDLING_UNSPECIFIED\x10\x00\x12\x0b\n\x07\x43OLLECT\x10\x01\x12\x0e\n\nNO_COLLECT\x10\x02\x12\x19\n\x15\x43OLLECT_AFTER_HW_TEST\x10\x03\x1a>\n\x14\x46ollowOnOrchestrator\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x18\n\x10\x61wait_completion\x18\x02 \x01(\x08J\x04\x08\x01\x10\x02\x1a\xd4\x0f\n\tArtifacts\x12@\n\tprebuilts\x18\x01 \x01(\x0e\x32-.chromiumos.BuilderConfig.Artifacts.Prebuilts\x12I\n\x0e\x61rtifact_types\x18\x02 \x03(\x0e\x32\x31.chromiumos.BuilderConfig.Artifacts.ArtifactTypes\x12\x1b\n\x13prebuilts_gs_bucket\x18\x03 \x01(\t\x12\x1b\n\x13\x61rtifacts_gs_bucket\x18\x04 \x01(\t\x12J\n\x11publish_artifacts\x18\x05 \x03(\x0b\x32/.chromiumos.BuilderConfig.Artifacts.PublishInfo\x12N\n\x0finput_artifacts\x18\x06 \x03(\x0b\x32\x35.chromiumos.BuilderConfig.Artifacts.InputArtifactInfo\x12>\n\x15\x61rtifact_profile_info\x18\x07 \x01(\x0b\x32\x1f.chromiumos.ArtifactProfileInfo\x12\x36\n\x0e\x61rtifacts_info\x18\x08 \x01(\x0b\x32\x1e.chromiumos.ArtifactsByService\x1a\x8c\x01\n\x0bPublishInfo\x12H\n\rpublish_types\x18\x02 \x03(\x0e\x32\x31.chromiumos.BuilderConfig.Artifacts.ArtifactTypes\x12\x1b\n\x13publish_gs_location\x18\x03 \x01(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\tJ\x04\x08\x01\x10\x02\x1a\x88\x01\n\x11InputArtifactInfo\x12N\n\x13input_artifact_type\x18\x01 \x01(\x0e\x32\x31.chromiumos.BuilderConfig.Artifacts.ArtifactTypes\x12#\n\x1binput_artifact_gs_locations\x18\x02 \x03(\t\"I\n\tPrebuilts\x12\x19\n\x15PREBUILTS_UNSPECIFIED\x10\x00\x12\n\n\x06PUBLIC\x10\x01\x12\x0b\n\x07PRIVATE\x10\x02\x12\x08\n\x04NONE\x10\x03\"\x86\t\n\rArtifactTypes\x12\x1e\n\x1a\x41RTIFACT_TYPES_UNSPECIFIED\x10\x00\x12\r\n\tIMAGE_ZIP\x10\x01\x12\x17\n\x13TEST_UPDATE_PAYLOAD\x10\x02\x12\x12\n\x0e\x41UTOTEST_FILES\x10\x03\x12\x0e\n\nTAST_FILES\x10\x04\x12\x17\n\x13PINNED_GUEST_IMAGES\x10\x05\x12\x0c\n\x08\x46IRMWARE\x10\x06\x12\x0f\n\x0b\x45\x42UILD_LOGS\x10\x07\x12\x13\n\x0f\x43HROMEOS_CONFIG\x10\x08\x12\x0e\n\nCPE_REPORT\x10\t\x12\x12\n\x0eIMAGE_ARCHIVES\x10\n\x12$\n UNVERIFIED_CHROME_LLVM_ORDERFILE\x10\x0b\x12\"\n\x1eVERIFIED_CHROME_LLVM_ORDERFILE\x10\x0c\x12\x1e\n\x1a\x43HROME_CLANG_WARNINGS_FILE\x10\r\x12\x1c\n\x18UNVERIFIED_LLVM_PGO_FILE\x10\x0e\x12)\n%UNVERIFIED_CHROME_BENCHMARK_AFDO_FILE\x10\x0f\x12\'\n#VERIFIED_CHROME_BENCHMARK_AFDO_FILE\x10\x10\x12!\n\x1dVERIFIED_KERNEL_CWP_AFDO_FILE\x10\x11\x12#\n\x1fUNVERIFIED_KERNEL_CWP_AFDO_FILE\x10\x12\x12#\n\x1fUNVERIFIED_CHROME_CWP_AFDO_FILE\x10\x13\x12!\n\x1dVERIFIED_CHROME_CWP_AFDO_FILE\x10\x14\x12\x1e\n\x1aVERIFIED_RELEASE_AFDO_FILE\x10\x15\x12)\n%UNVERIFIED_CHROME_BENCHMARK_PERF_FILE\x10\x16\x12\x17\n\x13\x43HROME_DEBUG_BINARY\x10\x17\x12\x1a\n\x16TOOLCHAIN_WARNING_LOGS\x10\x18\x12)\n%CHROME_AFDO_PROFILE_FOR_ANDROID_LINUX\x10\x19\x12\x19\n\x15\x43LANG_CRASH_DIAGNOSES\x10\x1a\x12\x13\n\x0f\x46PMCU_UNITTESTS\x10\x1b\x12\x0f\n\x0bGCE_TARBALL\x10\x1c\x12\x17\n\x13\x43OMPILER_RUSAGE_LOG\x10\x1d\x12\x14\n\x10\x46IRMWARE_TARBALL\x10\x1e\x12\x19\n\x15\x46IRMWARE_TARBALL_INFO\x10\x1f\x12\x11\n\rDEBUG_SYMBOLS\x10 \x12\x11\n\rFIRMWARE_LCOV\x10!\x12\r\n\tDLC_IMAGE\x10\"\x12\x1a\n\x16\x42REAKPAD_DEBUG_SYMBOLS\x10#\x12\x12\n\x0e\x42UILD_MANIFEST\x10$\x12\x0e\n\nUNIT_TESTS\x10%\x12\x13\n\x0fLICENSE_CREDITS\x10&\x12\x1b\n\x17\x43ODE_COVERAGE_LLVM_JSON\x10\'\x12\x19\n\x15SIMPLE_CHROME_SYSROOT\x10(\x12\x15\n\x11\x43HROME_EBUILD_ENV\x10)\x12\n\n\x06HWQUAL\x10*\x12\x11\n\rFACTORY_IMAGE\x10+\x1a\x1a\n\x06\x43hrome\x12\x10\n\x08internal\x18\x01 \x01(\x08\x1a\xae\x08\n\x05\x42uild\x12&\n\tuse_flags\x18\x01 \x03(\x0b\x32\x13.chromiumos.UseFlag\x12G\n\x0fportage_profile\x18\x02 \x01(\x0b\x32..chromiumos.BuilderConfig.Build.PortageProfile\x12\x1c\n\x14\x61pply_gerrit_changes\x18\x06 \x01(\x08\x12J\n\x11prepare_for_build\x18\x11 \x01(\x0b\x32/.chromiumos.BuilderConfig.Build.PrepareForBuild\x12=\n\nsdk_update\x18\x0c \x01(\x0b\x32).chromiumos.BuilderConfig.Build.SdkUpdate\x12K\n\x11install_toolchain\x18\r \x01(\x0b\x32\x30.chromiumos.BuilderConfig.Build.InstallToolchain\x12I\n\x10install_packages\x18\x10 \x01(\x0b\x32/.chromiumos.BuilderConfig.Build.InstallPackages\x12\x41\n\x0c\x62uild_images\x18\x0f \x01(\x0b\x32+.chromiumos.BuilderConfig.Build.BuildImages\x1a!\n\x0ePortageProfile\x12\x0f\n\x07profile\x18\x01 \x01(\t\x1aU\n\x0fPrepareForBuild\x12\x42\n\x0f\x61\x64\x64itional_args\x18\x01 \x01(\x0b\x32).chromiumos.PrepareForBuildAdditionalArgs\x1a#\n\tSdkUpdate\x12\x16\n\x0e\x63ompile_source\x18\x01 \x01(\x08\x1a*\n\x10InstallToolchain\x12\x16\n\x0e\x63ompile_source\x18\x01 \x01(\x08\x1a\xdd\x01\n\x0fInstallPackages\x12\x16\n\x0e\x63ompile_source\x18\x01 \x01(\x08\x12\x33\n\x08run_spec\x18\x02 \x01(\x0e\x32!.chromiumos.BuilderConfig.RunSpec\x12)\n\x08packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\x14\n\x0c\x64isable_goma\x18\x04 \x01(\x08\x12<\n\x0c\x64\x65pendencies\x18\x05 \x01(\x0e\x32&.chromiumos.BuilderConfig.Dependencies\x1as\n\x0b\x42uildImages\x12*\n\x0bimage_types\x18\x01 \x03(\x0e\x32\x15.chromiumos.ImageType\x12#\n\x1b\x64isable_rootfs_verification\x18\x02 \x01(\x08\x12\x13\n\x0b\x64isk_layout\x18\x03 \x01(\tJ\x04\x08\x03\x10\x06J\x04\x08\x07\x10\x0cJ\x04\x08\x0e\x10\x0f\x1a\x82\x02\n\tUnitTests\x12;\n\x10\x65\x62uilds_run_spec\x18\x05 \x01(\x0e\x32!.chromiumos.BuilderConfig.RunSpec\x12\x15\n\rempty_sysroot\x18\x06 \x01(\x08\x12)\n\x08packages\x18\x07 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12<\n\x0c\x64\x65pendencies\x18\x08 \x01(\x0e\x32&.chromiumos.BuilderConfig.Dependencies\x12\x32\n\x11package_blocklist\x18\t \x03(\x0b\x32\x17.chromiumos.PackageInfoJ\x04\x08\x04\x10\x05\"F\n\x07RunSpec\x12\x18\n\x14RUN_SPEC_UNSPECIFIED\x10\x00\x12\n\n\x06NO_RUN\x10\x01\x12\x07\n\x03RUN\x10\x02\x12\x0c\n\x08RUN_EXIT\x10\x03\"`\n\x0c\x44\x65pendencies\x12\x1c\n\x18\x44\x45PENDENCIES_UNSPECIFIED\x10\x00\x12\x14\n\x10\x41LL_DEPENDENCIES\x10\x01\x12\x1c\n\x18\x43L_AFFECTED_DEPENDENCIES\x10\x02\"D\n\x0e\x42uilderConfigs\x12\x32\n\x0f\x62uilder_configs\x18\x01 \x03(\x0b\x32\x19.chromiumos.BuilderConfigBY\n!com.google.chrome.crosinfra.protoZ4go.chromium.org/chromiumos/infra/proto/go/chromiumosb\x06proto3'
+  serialized_pb=b'\n\x1f\x63hromiumos/builder_config.proto\x12\nchromiumos\x1a\x17\x63hromiumos/common.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/wrappers.proto\"\xe0*\n\rBuilderConfig\x12(\n\x02id\x18\x01 \x01(\x0b\x32\x1c.chromiumos.BuilderConfig.Id\x12\x32\n\x07general\x18\x02 \x01(\x0b\x32!.chromiumos.BuilderConfig.General\x12<\n\x0corchestrator\x18\x03 \x01(\x0b\x32&.chromiumos.BuilderConfig.Orchestrator\x12\x36\n\tartifacts\x18\x04 \x01(\x0b\x32#.chromiumos.BuilderConfig.Artifacts\x12\x30\n\x06\x63hrome\x18\x05 \x01(\x0b\x32 .chromiumos.BuilderConfig.Chrome\x12.\n\x05\x62uild\x18\x06 \x01(\x0b\x32\x1f.chromiumos.BuilderConfig.Build\x12\x37\n\nunit_tests\x18\x07 \x01(\x0b\x32#.chromiumos.BuilderConfig.UnitTests\x1a\xb6\x01\n\x02Id\x12\x0c\n\x04name\x18\x01 \x01(\t\x12/\n\x04type\x18\x03 \x01(\x0e\x32!.chromiumos.BuilderConfig.Id.Type\"c\n\x04Type\x12\x14\n\x10TYPE_UNSPECIFIED\x10\x00\x12\x06\n\x02\x43Q\x10\x01\x12\x0e\n\nPOSTSUBMIT\x10\x02\x12\r\n\tTOOLCHAIN\x10\x03\x12\x11\n\rINFORMATIONAL\x10\x04\x12\x0b\n\x07RELEASE\x10\x05J\x04\x08\x02\x10\x03R\x06\x62ranch\x1a\xd6\x05\n\x07General\x12,\n\x08\x63ritical\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.BoolValue\x12\x42\n\x0b\x65nvironment\x18\x02 \x01(\x0e\x32-.chromiumos.BuilderConfig.General.Environment\x12;\n\x08run_when\x18\x03 \x01(\x0b\x32).chromiumos.BuilderConfig.General.RunWhen\x12\x31\n\rbroken_before\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x19\n\x11sdk_cache_version\x18\x05 \x01(\x05\x12\x10\n\x08unibuild\x18\x06 \x01(\x08\x12<\n\x08manifest\x18\x07 \x01(\x0e\x32*.chromiumos.BuilderConfig.General.Manifest\x12\x31\n\x11\x66irmware_location\x18\x08 \x01(\x0e\x32\x16.chromiumos.FwLocation\x1a\xc2\x01\n\x07RunWhen\x12<\n\x04mode\x18\x01 \x01(\x0e\x32..chromiumos.BuilderConfig.General.RunWhen.Mode\x12\x15\n\rfile_patterns\x18\x02 \x03(\t\"b\n\x04Mode\x12\x14\n\x10MODE_UNSPECIFIED\x10\x00\x12\x0e\n\nALWAYS_RUN\x10\x01\x12\x1a\n\x16ONLY_RUN_ON_FILE_MATCH\x10\x02\x12\x18\n\x14NO_RUN_ON_FILE_MATCH\x10\x03\"G\n\x0b\x45nvironment\x12\x1b\n\x17\x45NVIRONMENT_UNSPECIFIED\x10\x00\x12\x0e\n\nPRODUCTION\x10\x01\x12\x0b\n\x07STAGING\x10\x02\"=\n\x08Manifest\x12\x18\n\x14MANIFEST_UNSPECIFIED\x10\x00\x12\n\n\x06PUBLIC\x10\x01\x12\x0b\n\x07PRIVATE\x10\x02\x1a\xe2\x04\n\x0cOrchestrator\x12\x45\n\x0b\x63hild_specs\x18\x05 \x03(\x0b\x32\x30.chromiumos.BuilderConfig.Orchestrator.ChildSpec\x12\x31\n\x0egitiles_commit\x18\x02 \x01(\x0b\x32\x19.chromiumos.GitilesCommit\x12\x30\n\x0egerrit_changes\x18\x03 \x03(\x0b\x32\x18.chromiumos.GerritChange\x12[\n\x16\x66ollow_on_orchestrator\x18\x04 \x01(\x0b\x32;.chromiumos.BuilderConfig.Orchestrator.FollowOnOrchestrator\x12\x1e\n\x16require_stable_devices\x18\x06 \x01(\x08\x1a\xe2\x01\n\tChildSpec\x12\x0c\n\x04name\x18\x01 \x01(\t\x12Z\n\x10\x63ollect_handling\x18\x02 \x01(\x0e\x32@.chromiumos.BuilderConfig.Orchestrator.ChildSpec.CollectHandling\"k\n\x0f\x43ollectHandling\x12 \n\x1c\x43OLLECT_HANDLING_UNSPECIFIED\x10\x00\x12\x0b\n\x07\x43OLLECT\x10\x01\x12\x0e\n\nNO_COLLECT\x10\x02\x12\x19\n\x15\x43OLLECT_AFTER_HW_TEST\x10\x03\x1a>\n\x14\x46ollowOnOrchestrator\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x18\n\x10\x61wait_completion\x18\x02 \x01(\x08J\x04\x08\x01\x10\x02\x1a\xd4\x0f\n\tArtifacts\x12@\n\tprebuilts\x18\x01 \x01(\x0e\x32-.chromiumos.BuilderConfig.Artifacts.Prebuilts\x12I\n\x0e\x61rtifact_types\x18\x02 \x03(\x0e\x32\x31.chromiumos.BuilderConfig.Artifacts.ArtifactTypes\x12\x1b\n\x13prebuilts_gs_bucket\x18\x03 \x01(\t\x12\x1b\n\x13\x61rtifacts_gs_bucket\x18\x04 \x01(\t\x12J\n\x11publish_artifacts\x18\x05 \x03(\x0b\x32/.chromiumos.BuilderConfig.Artifacts.PublishInfo\x12N\n\x0finput_artifacts\x18\x06 \x03(\x0b\x32\x35.chromiumos.BuilderConfig.Artifacts.InputArtifactInfo\x12>\n\x15\x61rtifact_profile_info\x18\x07 \x01(\x0b\x32\x1f.chromiumos.ArtifactProfileInfo\x12\x36\n\x0e\x61rtifacts_info\x18\x08 \x01(\x0b\x32\x1e.chromiumos.ArtifactsByService\x1a\x8c\x01\n\x0bPublishInfo\x12H\n\rpublish_types\x18\x02 \x03(\x0e\x32\x31.chromiumos.BuilderConfig.Artifacts.ArtifactTypes\x12\x1b\n\x13publish_gs_location\x18\x03 \x01(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\tJ\x04\x08\x01\x10\x02\x1a\x88\x01\n\x11InputArtifactInfo\x12N\n\x13input_artifact_type\x18\x01 \x01(\x0e\x32\x31.chromiumos.BuilderConfig.Artifacts.ArtifactTypes\x12#\n\x1binput_artifact_gs_locations\x18\x02 \x03(\t\"I\n\tPrebuilts\x12\x19\n\x15PREBUILTS_UNSPECIFIED\x10\x00\x12\n\n\x06PUBLIC\x10\x01\x12\x0b\n\x07PRIVATE\x10\x02\x12\x08\n\x04NONE\x10\x03\"\x86\t\n\rArtifactTypes\x12\x1e\n\x1a\x41RTIFACT_TYPES_UNSPECIFIED\x10\x00\x12\r\n\tIMAGE_ZIP\x10\x01\x12\x17\n\x13TEST_UPDATE_PAYLOAD\x10\x02\x12\x12\n\x0e\x41UTOTEST_FILES\x10\x03\x12\x0e\n\nTAST_FILES\x10\x04\x12\x17\n\x13PINNED_GUEST_IMAGES\x10\x05\x12\x0c\n\x08\x46IRMWARE\x10\x06\x12\x0f\n\x0b\x45\x42UILD_LOGS\x10\x07\x12\x13\n\x0f\x43HROMEOS_CONFIG\x10\x08\x12\x0e\n\nCPE_REPORT\x10\t\x12\x12\n\x0eIMAGE_ARCHIVES\x10\n\x12$\n UNVERIFIED_CHROME_LLVM_ORDERFILE\x10\x0b\x12\"\n\x1eVERIFIED_CHROME_LLVM_ORDERFILE\x10\x0c\x12\x1e\n\x1a\x43HROME_CLANG_WARNINGS_FILE\x10\r\x12\x1c\n\x18UNVERIFIED_LLVM_PGO_FILE\x10\x0e\x12)\n%UNVERIFIED_CHROME_BENCHMARK_AFDO_FILE\x10\x0f\x12\'\n#VERIFIED_CHROME_BENCHMARK_AFDO_FILE\x10\x10\x12!\n\x1dVERIFIED_KERNEL_CWP_AFDO_FILE\x10\x11\x12#\n\x1fUNVERIFIED_KERNEL_CWP_AFDO_FILE\x10\x12\x12#\n\x1fUNVERIFIED_CHROME_CWP_AFDO_FILE\x10\x13\x12!\n\x1dVERIFIED_CHROME_CWP_AFDO_FILE\x10\x14\x12\x1e\n\x1aVERIFIED_RELEASE_AFDO_FILE\x10\x15\x12)\n%UNVERIFIED_CHROME_BENCHMARK_PERF_FILE\x10\x16\x12\x17\n\x13\x43HROME_DEBUG_BINARY\x10\x17\x12\x1a\n\x16TOOLCHAIN_WARNING_LOGS\x10\x18\x12)\n%CHROME_AFDO_PROFILE_FOR_ANDROID_LINUX\x10\x19\x12\x19\n\x15\x43LANG_CRASH_DIAGNOSES\x10\x1a\x12\x13\n\x0f\x46PMCU_UNITTESTS\x10\x1b\x12\x0f\n\x0bGCE_TARBALL\x10\x1c\x12\x17\n\x13\x43OMPILER_RUSAGE_LOG\x10\x1d\x12\x14\n\x10\x46IRMWARE_TARBALL\x10\x1e\x12\x19\n\x15\x46IRMWARE_TARBALL_INFO\x10\x1f\x12\x11\n\rDEBUG_SYMBOLS\x10 \x12\x11\n\rFIRMWARE_LCOV\x10!\x12\r\n\tDLC_IMAGE\x10\"\x12\x1a\n\x16\x42REAKPAD_DEBUG_SYMBOLS\x10#\x12\x12\n\x0e\x42UILD_MANIFEST\x10$\x12\x0e\n\nUNIT_TESTS\x10%\x12\x13\n\x0fLICENSE_CREDITS\x10&\x12\x1b\n\x17\x43ODE_COVERAGE_LLVM_JSON\x10\'\x12\x19\n\x15SIMPLE_CHROME_SYSROOT\x10(\x12\x15\n\x11\x43HROME_EBUILD_ENV\x10)\x12\n\n\x06HWQUAL\x10*\x12\x11\n\rFACTORY_IMAGE\x10+\x1a\x1a\n\x06\x43hrome\x12\x10\n\x08internal\x18\x01 \x01(\x08\x1a\xc6\x08\n\x05\x42uild\x12&\n\tuse_flags\x18\x01 \x03(\x0b\x32\x13.chromiumos.UseFlag\x12G\n\x0fportage_profile\x18\x02 \x01(\x0b\x32..chromiumos.BuilderConfig.Build.PortageProfile\x12\x1c\n\x14\x61pply_gerrit_changes\x18\x06 \x01(\x08\x12J\n\x11prepare_for_build\x18\x11 \x01(\x0b\x32/.chromiumos.BuilderConfig.Build.PrepareForBuild\x12=\n\nsdk_update\x18\x0c \x01(\x0b\x32).chromiumos.BuilderConfig.Build.SdkUpdate\x12K\n\x11install_toolchain\x18\r \x01(\x0b\x32\x30.chromiumos.BuilderConfig.Build.InstallToolchain\x12I\n\x10install_packages\x18\x10 \x01(\x0b\x32/.chromiumos.BuilderConfig.Build.InstallPackages\x12\x41\n\x0c\x62uild_images\x18\x0f \x01(\x0b\x32+.chromiumos.BuilderConfig.Build.BuildImages\x1a!\n\x0ePortageProfile\x12\x0f\n\x07profile\x18\x01 \x01(\t\x1aU\n\x0fPrepareForBuild\x12\x42\n\x0f\x61\x64\x64itional_args\x18\x01 \x01(\x0b\x32).chromiumos.PrepareForBuildAdditionalArgs\x1a#\n\tSdkUpdate\x12\x16\n\x0e\x63ompile_source\x18\x01 \x01(\x08\x1a*\n\x10InstallToolchain\x12\x16\n\x0e\x63ompile_source\x18\x01 \x01(\x08\x1a\xf5\x01\n\x0fInstallPackages\x12\x16\n\x0e\x63ompile_source\x18\x01 \x01(\x08\x12\x33\n\x08run_spec\x18\x02 \x01(\x0e\x32!.chromiumos.BuilderConfig.RunSpec\x12)\n\x08packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\x14\n\x0c\x64isable_goma\x18\x04 \x01(\x08\x12\x16\n\x0euse_remoteexec\x18\x06 \x01(\x08\x12<\n\x0c\x64\x65pendencies\x18\x05 \x01(\x0e\x32&.chromiumos.BuilderConfig.Dependencies\x1as\n\x0b\x42uildImages\x12*\n\x0bimage_types\x18\x01 \x03(\x0e\x32\x15.chromiumos.ImageType\x12#\n\x1b\x64isable_rootfs_verification\x18\x02 \x01(\x08\x12\x13\n\x0b\x64isk_layout\x18\x03 \x01(\tJ\x04\x08\x03\x10\x06J\x04\x08\x07\x10\x0cJ\x04\x08\x0e\x10\x0f\x1a\x82\x02\n\tUnitTests\x12;\n\x10\x65\x62uilds_run_spec\x18\x05 \x01(\x0e\x32!.chromiumos.BuilderConfig.RunSpec\x12\x15\n\rempty_sysroot\x18\x06 \x01(\x08\x12)\n\x08packages\x18\x07 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12<\n\x0c\x64\x65pendencies\x18\x08 \x01(\x0e\x32&.chromiumos.BuilderConfig.Dependencies\x12\x32\n\x11package_blocklist\x18\t \x03(\x0b\x32\x17.chromiumos.PackageInfoJ\x04\x08\x04\x10\x05\"F\n\x07RunSpec\x12\x18\n\x14RUN_SPEC_UNSPECIFIED\x10\x00\x12\n\n\x06NO_RUN\x10\x01\x12\x07\n\x03RUN\x10\x02\x12\x0c\n\x08RUN_EXIT\x10\x03\"`\n\x0c\x44\x65pendencies\x12\x1c\n\x18\x44\x45PENDENCIES_UNSPECIFIED\x10\x00\x12\x14\n\x10\x41LL_DEPENDENCIES\x10\x01\x12\x1c\n\x18\x43L_AFFECTED_DEPENDENCIES\x10\x02\"D\n\x0e\x42uilderConfigs\x12\x32\n\x0f\x62uilder_configs\x18\x01 \x03(\x0b\x32\x19.chromiumos.BuilderConfigBY\n!com.google.chrome.crosinfra.protoZ4go.chromium.org/chromiumos/infra/proto/go/chromiumosb\x06proto3'
   ,
   dependencies=[chromiumos_dot_common__pb2.DESCRIPTOR,google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,google_dot_protobuf_dot_wrappers__pb2.DESCRIPTOR,])
 
@@ -198,8 +198,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1838,
-  serialized_end=1945,
+  serialized_start=1870,
+  serialized_end=1977,
 )
 _sym_db.RegisterEnumDescriptor(_BUILDERCONFIG_ORCHESTRATOR_CHILDSPEC_COLLECTHANDLING)
 
@@ -233,8 +233,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2788,
-  serialized_end=2861,
+  serialized_start=2820,
+  serialized_end=2893,
 )
 _sym_db.RegisterEnumDescriptor(_BUILDERCONFIG_ARTIFACTS_PREBUILTS)
 
@@ -468,8 +468,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2864,
-  serialized_end=4022,
+  serialized_start=2896,
+  serialized_end=4054,
 )
 _sym_db.RegisterEnumDescriptor(_BUILDERCONFIG_ARTIFACTS_ARTIFACTTYPES)
 
@@ -503,8 +503,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=5386,
-  serialized_end=5456,
+  serialized_start=5442,
+  serialized_end=5512,
 )
 _sym_db.RegisterEnumDescriptor(_BUILDERCONFIG_RUNSPEC)
 
@@ -533,8 +533,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=5458,
-  serialized_end=5554,
+  serialized_start=5514,
+  serialized_end=5610,
 )
 _sym_db.RegisterEnumDescriptor(_BUILDERCONFIG_DEPENDENCIES)
 
@@ -734,8 +734,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1719,
-  serialized_end=1945,
+  serialized_start=1751,
+  serialized_end=1977,
 )
 
 _BUILDERCONFIG_ORCHESTRATOR_FOLLOWONORCHESTRATOR = _descriptor.Descriptor(
@@ -772,8 +772,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1947,
-  serialized_end=2009,
+  serialized_start=1979,
+  serialized_end=2041,
 )
 
 _BUILDERCONFIG_ORCHESTRATOR = _descriptor.Descriptor(
@@ -812,6 +812,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='require_stable_devices', full_name='chromiumos.BuilderConfig.Orchestrator.require_stable_devices', index=4,
+      number=6, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -825,7 +832,7 @@
   oneofs=[
   ],
   serialized_start=1437,
-  serialized_end=2015,
+  serialized_end=2047,
 )
 
 _BUILDERCONFIG_ARTIFACTS_PUBLISHINFO = _descriptor.Descriptor(
@@ -869,8 +876,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2507,
-  serialized_end=2647,
+  serialized_start=2539,
+  serialized_end=2679,
 )
 
 _BUILDERCONFIG_ARTIFACTS_INPUTARTIFACTINFO = _descriptor.Descriptor(
@@ -907,8 +914,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2650,
-  serialized_end=2786,
+  serialized_start=2682,
+  serialized_end=2818,
 )
 
 _BUILDERCONFIG_ARTIFACTS = _descriptor.Descriptor(
@@ -989,8 +996,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2018,
-  serialized_end=4022,
+  serialized_start=2050,
+  serialized_end=4054,
 )
 
 _BUILDERCONFIG_CHROME = _descriptor.Descriptor(
@@ -1020,8 +1027,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4024,
-  serialized_end=4050,
+  serialized_start=4056,
+  serialized_end=4082,
 )
 
 _BUILDERCONFIG_BUILD_PORTAGEPROFILE = _descriptor.Descriptor(
@@ -1051,8 +1058,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4563,
-  serialized_end=4596,
+  serialized_start=4595,
+  serialized_end=4628,
 )
 
 _BUILDERCONFIG_BUILD_PREPAREFORBUILD = _descriptor.Descriptor(
@@ -1082,8 +1089,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4598,
-  serialized_end=4683,
+  serialized_start=4630,
+  serialized_end=4715,
 )
 
 _BUILDERCONFIG_BUILD_SDKUPDATE = _descriptor.Descriptor(
@@ -1113,8 +1120,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4685,
-  serialized_end=4720,
+  serialized_start=4717,
+  serialized_end=4752,
 )
 
 _BUILDERCONFIG_BUILD_INSTALLTOOLCHAIN = _descriptor.Descriptor(
@@ -1144,8 +1151,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4722,
-  serialized_end=4764,
+  serialized_start=4754,
+  serialized_end=4796,
 )
 
 _BUILDERCONFIG_BUILD_INSTALLPACKAGES = _descriptor.Descriptor(
@@ -1185,7 +1192,14 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='dependencies', full_name='chromiumos.BuilderConfig.Build.InstallPackages.dependencies', index=4,
+      name='use_remoteexec', full_name='chromiumos.BuilderConfig.Build.InstallPackages.use_remoteexec', index=4,
+      number=6, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='dependencies', full_name='chromiumos.BuilderConfig.Build.InstallPackages.dependencies', index=5,
       number=5, type=14, cpp_type=8, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
@@ -1203,8 +1217,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4767,
-  serialized_end=4988,
+  serialized_start=4799,
+  serialized_end=5044,
 )
 
 _BUILDERCONFIG_BUILD_BUILDIMAGES = _descriptor.Descriptor(
@@ -1248,8 +1262,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4990,
-  serialized_end=5105,
+  serialized_start=5046,
+  serialized_end=5161,
 )
 
 _BUILDERCONFIG_BUILD = _descriptor.Descriptor(
@@ -1328,8 +1342,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4053,
-  serialized_end=5123,
+  serialized_start=4085,
+  serialized_end=5179,
 )
 
 _BUILDERCONFIG_UNITTESTS = _descriptor.Descriptor(
@@ -1387,8 +1401,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5126,
-  serialized_end=5384,
+  serialized_start=5182,
+  serialized_end=5440,
 )
 
 _BUILDERCONFIG = _descriptor.Descriptor(
@@ -1463,7 +1477,7 @@
   oneofs=[
   ],
   serialized_start=138,
-  serialized_end=5554,
+  serialized_end=5610,
 )
 
 
@@ -1494,8 +1508,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5556,
-  serialized_end=5624,
+  serialized_start=5612,
+  serialized_end=5680,
 )
 
 _BUILDERCONFIG_ID.fields_by_name['type'].enum_type = _BUILDERCONFIG_ID_TYPE
diff --git a/api/gen/chromiumos/common_pb2.py b/api/gen/chromiumos/common_pb2.py
index 8143ad5..b51293d 100644
--- a/api/gen/chromiumos/common_pb2.py
+++ b/api/gen/chromiumos/common_pb2.py
@@ -20,7 +20,7 @@
   syntax='proto3',
   serialized_options=b'\n!com.google.chrome.crosinfra.protoZ4go.chromium.org/chromiumos/infra/proto/go/chromiumos',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n\x17\x63hromiumos/common.proto\x12\nchromiumos\"\x1b\n\x0b\x42uildTarget\x12\x0c\n\x04name\x18\x01 \x01(\t\"\'\n\x07GcsPath\x12\x0e\n\x06\x62ucket\x18\x01 \x01(\t\x12\x0c\n\x04path\x18\x02 \x01(\t\"\xd0\x01\n\x06\x43hroot\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x11\n\tcache_dir\x18\x02 \x01(\t\x12)\n\x03\x65nv\x18\x03 \x01(\x0b\x32\x1c.chromiumos.Chroot.ChrootEnv\x12\x12\n\nchrome_dir\x18\x04 \x01(\t\x1aZ\n\tChrootEnv\x12&\n\tuse_flags\x18\x01 \x03(\x0b\x32\x13.chromiumos.UseFlag\x12%\n\x08\x66\x65\x61tures\x18\x02 \x03(\x0b\x32\x13.chromiumos.FeatureJ\x04\x08\x05\x10\x06R\x04goma\"\x1a\n\x07\x46\x65\x61ture\x12\x0f\n\x07\x66\x65\x61ture\x18\x01 \x01(\t\"\xcf\x02\n\nGomaConfig\x12\x10\n\x08goma_dir\x18\x01 \x01(\t\x12\x18\n\x10goma_client_json\x18\x02 \x01(\t\x12\x19\n\x11\x63hromeos_goma_dir\x18\x03 \x01(\t\x12:\n\rgoma_approach\x18\x04 \x01(\x0e\x32#.chromiumos.GomaConfig.GomaApproach\x12&\n\x07log_dir\x18\x05 \x01(\x0b\x32\x15.chromiumos.SyncedDir\x12\x12\n\nstats_file\x18\x06 \x01(\t\x12\x15\n\rcounterz_file\x18\x07 \x01(\t\"k\n\x0cGomaApproach\x12\x1d\n\x19GOMA_APPROACH_UNSPECIFIED\x10\x00\x12\x0b\n\x07\x44\x45\x46\x41ULT\x10\x01\x12\x0c\n\x08RBE_PROD\x10\x02\x12\x0f\n\x0bRBE_STAGING\x10\x03\x12\x10\n\x0cRBE_CHROMEOS\x10\x04\"M\n\rGomaArtifacts\x12\x12\n\nstats_file\x18\x01 \x01(\t\x12\x15\n\rcounterz_file\x18\x02 \x01(\t\x12\x11\n\tlog_files\x18\x03 \x03(\t\"F\n\x0bPackageInfo\x12\x14\n\x0cpackage_name\x18\x01 \x01(\t\x12\x10\n\x08\x63\x61tegory\x18\x02 \x01(\t\x12\x0f\n\x07version\x18\x03 \x01(\t\"\x17\n\x07Profile\x12\x0c\n\x04name\x18\x01 \x01(\t\"\xa8\x01\n\x10PackageIndexInfo\x12\x14\n\x0csnapshot_sha\x18\x01 \x01(\t\x12\x17\n\x0fsnapshot_number\x18\x02 \x01(\x05\x12-\n\x0c\x62uild_target\x18\x03 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x10\n\x08location\x18\x04 \x01(\t\x12$\n\x07profile\x18\x05 \x01(\x0b\x32\x13.chromiumos.Profile\"w\n\x04Path\x12\x0c\n\x04path\x18\x01 \x01(\t\x12+\n\x08location\x18\x02 \x01(\x0e\x32\x19.chromiumos.Path.Location\"4\n\x08Location\x12\x0f\n\x0bNO_LOCATION\x10\x00\x12\n\n\x06INSIDE\x10\x01\x12\x0b\n\x07OUTSIDE\x10\x02\",\n\nResultPath\x12\x1e\n\x04path\x18\x01 \x01(\x0b\x32\x10.chromiumos.Path\"\x18\n\tSyncedDir\x12\x0b\n\x03\x64ir\x18\x01 \x01(\t\"O\n\x0cGerritChange\x12\x0c\n\x04host\x18\x01 \x01(\t\x12\x0f\n\x07project\x18\x02 \x01(\t\x12\x0e\n\x06\x63hange\x18\x03 \x01(\x03\x12\x10\n\x08patchset\x18\x04 \x01(\x03\"Y\n\rGitilesCommit\x12\x0c\n\x04host\x18\x01 \x01(\t\x12\x0f\n\x07project\x18\x02 \x01(\t\x12\n\n\x02id\x18\x03 \x01(\t\x12\x0b\n\x03ref\x18\x04 \x01(\t\x12\x10\n\x08position\x18\x05 \x01(\r\"\x17\n\x07UseFlag\x12\x0c\n\x04\x66lag\x18\x01 \x01(\t\"\xb8\x02\n\x0eReleaseBuilder\x12\x39\n\tmilestone\x18\x01 \x01(\x0b\x32$.chromiumos.ReleaseBuilder.MilestoneH\x00\x12\x16\n\x0e\x62uild_schedule\x18\x02 \x01(\t\x12\x38\n\x0f\x65xpiration_date\x18\x03 \x01(\x0b\x32\x1f.chromiumos.ReleaseBuilder.Date\x1a\x15\n\x04\x44\x61te\x12\r\n\x05value\x18\x01 \x01(\t\x1am\n\tMilestone\x12\x0e\n\x06number\x18\x01 \x01(\x05\x12;\n\x12target_branch_date\x18\x02 \x01(\x0b\x32\x1f.chromiumos.ReleaseBuilder.Date\x12\x13\n\x0b\x62ranch_name\x18\x03 \x01(\tB\x13\n\x11milestone_message\"?\n\x0fReleaseBuilders\x12,\n\x08\x62uilders\x18\x01 \x03(\x0b\x32\x1a.chromiumos.ReleaseBuilder\"\xf4\x01\n\x0fReleaseChannels\x12J\n\x10release_channels\x18\x01 \x03(\x0b\x32\x30.chromiumos.ReleaseChannels.ReleaseChannelsEntry\x1a\x34\n\x0b\x43hannelList\x12%\n\x08\x63hannels\x18\x01 \x03(\x0e\x32\x13.chromiumos.Channel\x1a_\n\x14ReleaseChannelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\x36\n\x05value\x18\x02 \x01(\x0b\x32\'.chromiumos.ReleaseChannels.ChannelList:\x02\x38\x01\"&\n\nProtoBytes\x12\x18\n\x10serialized_proto\x18\x01 \x01(\x0c\"q\n\x1dPrepareForBuildAdditionalArgs\x12\x1c\n\x12\x63hrome_cwp_profile\x18\x01 \x01(\tH\x00\x12\x18\n\x0ekernel_version\x18\x02 \x01(\tH\x00\x42\x18\n\x16prepare_for_build_args\"A\n\x0b\x41\x66\x64oRelease\x12\x1a\n\x12\x63hrome_cwp_profile\x18\x01 \x01(\t\x12\x16\n\x0eimage_build_id\x18\x02 \x01(\x03\"\x97\x01\n\x13\x41rtifactProfileInfo\x12\x1c\n\x12\x63hrome_cwp_profile\x18\x01 \x01(\tH\x00\x12\x18\n\x0ekernel_version\x18\x02 \x01(\tH\x00\x12/\n\x0c\x61\x66\x64o_release\x18\x03 \x01(\x0b\x32\x17.chromiumos.AfdoReleaseH\x00\x42\x17\n\x15\x61rtifact_profile_info\"\xbe+\n\x12\x41rtifactsByService\x12\x35\n\x06legacy\x18\x01 \x01(\x0b\x32%.chromiumos.ArtifactsByService.Legacy\x12;\n\ttoolchain\x18\x02 \x01(\x0b\x32(.chromiumos.ArtifactsByService.Toolchain\x12\x33\n\x05image\x18\x03 \x01(\x0b\x32$.chromiumos.ArtifactsByService.Image\x12\x37\n\x07package\x18\x04 \x01(\x0b\x32&.chromiumos.ArtifactsByService.Package\x12\x37\n\x07sysroot\x18\x05 \x01(\x0b\x32&.chromiumos.ArtifactsByService.Sysroot\x12\x31\n\x04test\x18\x06 \x01(\x0b\x32#.chromiumos.ArtifactsByService.Test\x12\x35\n\x0cprofile_info\x18\x07 \x01(\x0b\x32\x1f.chromiumos.ArtifactProfileInfo\x12\x39\n\x08\x66irmware\x18\x08 \x01(\x0b\x32\'.chromiumos.ArtifactsByService.Firmware\x12\x33\n\x05infra\x18\t \x01(\x0b\x32$.chromiumos.ArtifactsByService.Infra\x1a\xb0\x01\n\x16\x43odeCoverageUploadInfo\x12]\n\rcoverage_type\x18\x01 \x01(\x0e\x32\x46.chromiumos.ArtifactsByService.CodeCoverageUploadInfo.CodeCoverageType\"7\n\x10\x43odeCoverageType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x08\n\x04LLVM\x10\x01\x12\x08\n\x04LCOV\x10\x02\x1a\xb2\x05\n\x06Legacy\x12K\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x32.chromiumos.ArtifactsByService.Legacy.ArtifactInfo\x12L\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x32.chromiumos.ArtifactsByService.Legacy.ArtifactInfo\x1a\xe2\x01\n\x0c\x41rtifactInfo\x12J\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x32.chromiumos.ArtifactsByService.Legacy.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\t\x12J\n\x11publish_condition\x18\x05 \x01(\x0e\x32/.chromiumos.ArtifactsByService.PublishConditionJ\x04\x08\x03\x10\x04R\x0cprofile_info\"\xa7\x02\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\r\n\tIMAGE_ZIP\x10\x01\x12\x17\n\x13TEST_UPDATE_PAYLOAD\x10\x02\x12\x12\n\x0e\x41UTOTEST_FILES\x10\x03\x12\x0e\n\nTAST_FILES\x10\x04\x12\x17\n\x13PINNED_GUEST_IMAGES\x10\x05\x12\x0c\n\x08\x46IRMWARE\x10\x06\x12\x0f\n\x0b\x45\x42UILD_LOGS\x10\x07\x12\x13\n\x0f\x43HROMEOS_CONFIG\x10\x08\x12\x0e\n\nCPE_REPORT\x10\t\x12\x12\n\x0eIMAGE_ARCHIVES\x10\n\x12\x13\n\x0f\x46PMCU_UNITTESTS\x10\x1b\x12\x0f\n\x0bGCE_TARBALL\x10\x1c\x12\x11\n\rDEBUG_SYMBOLS\x10 \"\x04\x08\x0b\x10\x1a\"\x04\x08\x1d\x10\x1f\"\x04\x08!\x10+\x1a\xff\x07\n\tToolchain\x12N\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x35.chromiumos.ArtifactsByService.Toolchain.ArtifactInfo\x12O\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x35.chromiumos.ArtifactsByService.Toolchain.ArtifactInfo\x1a\xd1\x01\n\x0c\x41rtifactInfo\x12M\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x35.chromiumos.ArtifactsByService.Toolchain.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\t\x12J\n\x11publish_condition\x18\x05 \x01(\x0e\x32/.chromiumos.ArtifactsByService.PublishCondition\"\xfc\x04\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12$\n UNVERIFIED_CHROME_LLVM_ORDERFILE\x10\x0b\x12\"\n\x1eVERIFIED_CHROME_LLVM_ORDERFILE\x10\x0c\x12\x1e\n\x1a\x43HROME_CLANG_WARNINGS_FILE\x10\r\x12\x1c\n\x18UNVERIFIED_LLVM_PGO_FILE\x10\x0e\x12)\n%UNVERIFIED_CHROME_BENCHMARK_AFDO_FILE\x10\x0f\x12\'\n#VERIFIED_CHROME_BENCHMARK_AFDO_FILE\x10\x10\x12!\n\x1dVERIFIED_KERNEL_CWP_AFDO_FILE\x10\x11\x12#\n\x1fUNVERIFIED_KERNEL_CWP_AFDO_FILE\x10\x12\x12#\n\x1fUNVERIFIED_CHROME_CWP_AFDO_FILE\x10\x13\x12!\n\x1dVERIFIED_CHROME_CWP_AFDO_FILE\x10\x14\x12\x1e\n\x1aVERIFIED_RELEASE_AFDO_FILE\x10\x15\x12)\n%UNVERIFIED_CHROME_BENCHMARK_PERF_FILE\x10\x16\x12\x17\n\x13\x43HROME_DEBUG_BINARY\x10\x17\x12\x1a\n\x16TOOLCHAIN_WARNING_LOGS\x10\x18\x12)\n%CHROME_AFDO_PROFILE_FOR_ANDROID_LINUX\x10\x19\x12\x19\n\x15\x43LANG_CRASH_DIAGNOSES\x10\x1a\x12\x17\n\x13\x43OMPILER_RUSAGE_LOG\x10\x1d\"\x04\x08\x01\x10\n\"\x04\x08\x1b\x10\x1c\"\x04\x08\x1e\x10+\x1a\xda\x03\n\x05Image\x12J\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x31.chromiumos.ArtifactsByService.Image.ArtifactInfo\x12K\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x31.chromiumos.ArtifactsByService.Image.ArtifactInfo\x1a\xcd\x01\n\x0c\x41rtifactInfo\x12I\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x31.chromiumos.ArtifactsByService.Image.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\t\x12J\n\x11publish_condition\x18\x05 \x01(\x0e\x32/.chromiumos.ArtifactsByService.PublishCondition\"h\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\r\n\tDLC_IMAGE\x10\"\x12\x13\n\x0fLICENSE_CREDITS\x10&\x12\x11\n\rFACTORY_IMAGE\x10+\"\x04\x08\x01\x10!\"\x04\x08#\x10%\"\x04\x08\'\x10*\x1a\x9f\x03\n\x07Package\x12L\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x33.chromiumos.ArtifactsByService.Package.ArtifactInfo\x12M\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x33.chromiumos.ArtifactsByService.Package.ArtifactInfo\x1a\xcf\x01\n\x0c\x41rtifactInfo\x12K\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x33.chromiumos.ArtifactsByService.Package.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\t\x12J\n\x11publish_condition\x18\x05 \x01(\x0e\x32/.chromiumos.ArtifactsByService.PublishCondition\"%\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\"\x04\x08\x01\x10+\x1a\x8d\x04\n\x07Sysroot\x12L\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x33.chromiumos.ArtifactsByService.Sysroot.ArtifactInfo\x12M\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x33.chromiumos.ArtifactsByService.Sysroot.ArtifactInfo\x1a\xcf\x01\n\x0c\x41rtifactInfo\x12K\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x33.chromiumos.ArtifactsByService.Sysroot.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\t\x12J\n\x11publish_condition\x18\x05 \x01(\x0e\x32/.chromiumos.ArtifactsByService.PublishCondition\"\x92\x01\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x11\n\rDEBUG_SYMBOLS\x10 \x12\x1a\n\x16\x42REAKPAD_DEBUG_SYMBOLS\x10#\x12\x19\n\x15SIMPLE_CHROME_SYSROOT\x10(\x12\x15\n\x11\x43HROME_EBUILD_ENV\x10)\"\x04\x08\x01\x10\x1f\"\x04\x08!\x10\"\"\x04\x08$\x10\'\x1a\xb2\x04\n\x04Test\x12I\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x30.chromiumos.ArtifactsByService.Test.ArtifactInfo\x12J\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x30.chromiumos.ArtifactsByService.Test.ArtifactInfo\x1a\xa6\x02\n\x0c\x41rtifactInfo\x12H\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x30.chromiumos.ArtifactsByService.Test.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\t\x12J\n\x11publish_condition\x18\x05 \x01(\x0e\x32/.chromiumos.ArtifactsByService.PublishCondition\x12X\n\x19\x63ode_coverage_upload_info\x18\x06 \x01(\x0b\x32\x35.chromiumos.ArtifactsByService.CodeCoverageUploadInfo\"j\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x0e\n\nUNIT_TESTS\x10%\x12\x1b\n\x17\x43ODE_COVERAGE_LLVM_JSON\x10\'\x12\n\n\x06HWQUAL\x10*\"\x04\x08\x01\x10$\"\x04\x08&\x10&\"\x04\x08(\x10)\x1a\xf7\x04\n\x08\x46irmware\x12M\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x34.chromiumos.ArtifactsByService.Firmware.ArtifactInfo\x12N\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x34.chromiumos.ArtifactsByService.Firmware.ArtifactInfo\x1a\xd4\x02\n\x0c\x41rtifactInfo\x12L\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x34.chromiumos.ArtifactsByService.Firmware.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\t\x12J\n\x11publish_condition\x18\x05 \x01(\x0e\x32/.chromiumos.ArtifactsByService.PublishCondition\x12(\n\x08location\x18\x06 \x01(\x0e\x32\x16.chromiumos.FwLocation\x12X\n\x19\x63ode_coverage_upload_info\x18\x07 \x01(\x0b\x32\x35.chromiumos.ArtifactsByService.CodeCoverageUploadInfo\"u\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x14\n\x10\x46IRMWARE_TARBALL\x10\x1e\x12\x19\n\x15\x46IRMWARE_TARBALL_INFO\x10\x1f\x12\x11\n\rFIRMWARE_LCOV\x10!\"\x04\x08\x01\x10\x1d\"\x04\x08 \x10 \"\x04\x08\"\x10+\x1a\xb1\x03\n\x05Infra\x12J\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x31.chromiumos.ArtifactsByService.Infra.ArtifactInfo\x12K\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x31.chromiumos.ArtifactsByService.Infra.ArtifactInfo\x1a\xcd\x01\n\x0c\x41rtifactInfo\x12I\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x31.chromiumos.ArtifactsByService.Infra.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\t\x12J\n\x11publish_condition\x18\x05 \x01(\x0e\x32/.chromiumos.ArtifactsByService.PublishCondition\"?\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x12\n\x0e\x42UILD_MANIFEST\x10$\"\x04\x08\x01\x10#\"\x04\x08%\x10+\"W\n\x10PublishCondition\x12\x17\n\x13PUBLISH_UNSPECIFIED\x10\x00\x12\x16\n\x12PUBLISH_ON_SUCCESS\x10\x01\x12\x12\n\x0ePUBLISH_ALWAYS\x10\x02\"\x8e\x12\n\x1aUploadedArtifactsByService\x12=\n\x06legacy\x18\x01 \x01(\x0b\x32-.chromiumos.UploadedArtifactsByService.Legacy\x12\x43\n\ttoolchain\x18\x02 \x01(\x0b\x32\x30.chromiumos.UploadedArtifactsByService.Toolchain\x12;\n\x05image\x18\x03 \x01(\x0b\x32,.chromiumos.UploadedArtifactsByService.Image\x12?\n\x07package\x18\x04 \x01(\x0b\x32..chromiumos.UploadedArtifactsByService.Package\x12?\n\x07sysroot\x18\x05 \x01(\x0b\x32..chromiumos.UploadedArtifactsByService.Sysroot\x12\x39\n\x04test\x18\x06 \x01(\x0b\x32+.chromiumos.UploadedArtifactsByService.Test\x12\x41\n\x08\x66irmware\x18\x07 \x01(\x0b\x32/.chromiumos.UploadedArtifactsByService.Firmware\x12;\n\x05infra\x18\x08 \x01(\x0b\x32,.chromiumos.UploadedArtifactsByService.Infra\x1a\xd5\x01\n\x06Legacy\x12N\n\tartifacts\x18\x01 \x03(\x0b\x32;.chromiumos.UploadedArtifactsByService.Legacy.ArtifactPaths\x1a{\n\rArtifactPaths\x12I\n\rartifact_type\x18\x01 \x01(\x0e\x32\x32.chromiumos.ArtifactsByService.Legacy.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path\x1a\xde\x01\n\tToolchain\x12Q\n\tartifacts\x18\x01 \x03(\x0b\x32>.chromiumos.UploadedArtifactsByService.Toolchain.ArtifactPaths\x1a~\n\rArtifactPaths\x12L\n\rartifact_type\x18\x01 \x01(\x0e\x32\x35.chromiumos.ArtifactsByService.Toolchain.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path\x1a\xd2\x01\n\x05Image\x12M\n\tartifacts\x18\x01 \x03(\x0b\x32:.chromiumos.UploadedArtifactsByService.Image.ArtifactPaths\x1az\n\rArtifactPaths\x12H\n\rartifact_type\x18\x01 \x01(\x0e\x32\x31.chromiumos.ArtifactsByService.Image.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path\x1a\xd8\x01\n\x07Package\x12O\n\tartifacts\x18\x01 \x03(\x0b\x32<.chromiumos.UploadedArtifactsByService.Package.ArtifactPaths\x1a|\n\rArtifactPaths\x12J\n\rartifact_type\x18\x01 \x01(\x0e\x32\x33.chromiumos.ArtifactsByService.Package.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path\x1a\xd8\x01\n\x07Sysroot\x12O\n\tartifacts\x18\x01 \x03(\x0b\x32<.chromiumos.UploadedArtifactsByService.Sysroot.ArtifactPaths\x1a|\n\rArtifactPaths\x12J\n\rartifact_type\x18\x01 \x01(\x0e\x32\x33.chromiumos.ArtifactsByService.Sysroot.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path\x1a\xcf\x01\n\x04Test\x12L\n\tartifacts\x18\x01 \x03(\x0b\x32\x39.chromiumos.UploadedArtifactsByService.Test.ArtifactPaths\x1ay\n\rArtifactPaths\x12G\n\rartifact_type\x18\x01 \x01(\x0e\x32\x30.chromiumos.ArtifactsByService.Test.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path\x1a\x86\x02\n\x08\x46irmware\x12P\n\tartifacts\x18\x01 \x03(\x0b\x32=.chromiumos.UploadedArtifactsByService.Firmware.ArtifactPaths\x1a\xa7\x01\n\rArtifactPaths\x12K\n\rartifact_type\x18\x01 \x01(\x0e\x32\x34.chromiumos.ArtifactsByService.Firmware.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path\x12(\n\x08location\x18\x03 \x01(\x0e\x32\x16.chromiumos.FwLocation\x1a\xd2\x01\n\x05Infra\x12M\n\tartifacts\x18\x01 \x03(\x0b\x32:.chromiumos.UploadedArtifactsByService.Infra.ArtifactPaths\x1az\n\rArtifactPaths\x12H\n\rartifact_type\x18\x01 \x01(\x0e\x32\x31.chromiumos.ArtifactsByService.Infra.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path*\xca\x04\n\tImageType\x12\x18\n\x14IMAGE_TYPE_UNDEFINED\x10\x00\x12\x13\n\x0fIMAGE_TYPE_BASE\x10\x01\x12\x12\n\x0eIMAGE_TYPE_DEV\x10\x02\x12\x13\n\x0fIMAGE_TYPE_TEST\x10\x03\x12\x16\n\x12IMAGE_TYPE_BASE_VM\x10\x04\x12\x16\n\x12IMAGE_TYPE_TEST_VM\x10\x05\x12\x17\n\x13IMAGE_TYPE_RECOVERY\x10\x06\x12\x16\n\x12IMAGE_TYPE_FACTORY\x10\x07\x12\x17\n\x13IMAGE_TYPE_FIRMWARE\x10\x08\x12\x1c\n\x18IMAGE_TYPE_CR50_FIRMWARE\x10\t\x12\x1c\n\x18IMAGE_TYPE_BASE_GUEST_VM\x10\n\x12\x1c\n\x18IMAGE_TYPE_TEST_GUEST_VM\x10\x0b\x12\x12\n\x0eIMAGE_TYPE_DLC\x10\x0c\x12\x1b\n\x17IMAGE_TYPE_GSC_FIRMWARE\x10\r\x12\x1e\n\x1aIMAGE_TYPE_ACCESSORY_USBPD\x10\x0e\x12\x1e\n\x1aIMAGE_TYPE_ACCESSORY_RWSIG\x10\x0f*\x04\x42\x41SE*\x04TEST*\x03\x44\x45V*\x07\x42\x41SE_VM*\x07TEST_VM*\x08RECOVERY*\x07\x46\x41\x43TORY*\x08\x46IRMWARE*\rCR50_FIRMWARE*\rBASE_GUEST_VM*\rTEST_GUEST_VM*\x03\x44LC*\x0cGSC_FIRMWARE*\x0f\x41\x43\x43\x45SSORY_USBPD*\x0f\x41\x43\x43\x45SSORY_RWSIG*\x80\x01\n\x07\x43hannel\x12\x17\n\x13\x43HANNEL_UNSPECIFIED\x10\x00\x12\x12\n\x0e\x43HANNEL_STABLE\x10\x01\x12\x10\n\x0c\x43HANNEL_BETA\x10\x02\x12\x0f\n\x0b\x43HANNEL_DEV\x10\x03\x12\x12\n\x0e\x43HANNEL_CANARY\x10\x04\x12\x11\n\rCHANNEL_RUBIK\x10\x05*l\n\tDeltaType\x12\x11\n\rDELTA_UNKNOWN\x10\x00\x12\x0c\n\x08NO_DELTA\x10\x01\x12\x07\n\x03\x46SI\x10\x02\x12\r\n\tMILESTONE\x10\x03\x12\t\n\x05OMAHA\x10\x04\x12\x12\n\x0eSTEPPING_STONE\x10\x05\x12\x07\n\x03N2N\x10\x06*^\n\nFwLocation\x12\x17\n\x13\x46W_LOCATION_UNKNOWN\x10\x00\x12\x0f\n\x0bPLATFORM_EC\x10\x01\x12\x13\n\x0fPLATFORM_ZEPHYR\x10\x02\x12\x11\n\rPLATFORM_TI50\x10\x03*f\n\x10\x41\x46\x44OArtifactType\x12\r\n\tNONE_TYPE\x10\x00\x12\r\n\tORDERFILE\x10\x01\x12\x12\n\x0e\x42\x45NCHMARK_AFDO\x10\x02\x12\x0f\n\x0bKERNEL_AFDO\x10\x03\x12\x0f\n\x0b\x43HROME_AFDO\x10\x04\x42Y\n!com.google.chrome.crosinfra.protoZ4go.chromium.org/chromiumos/infra/proto/go/chromiumosb\x06proto3'
+  serialized_pb=b'\n\x17\x63hromiumos/common.proto\x12\nchromiumos\"\x1b\n\x0b\x42uildTarget\x12\x0c\n\x04name\x18\x01 \x01(\t\"\'\n\x07GcsPath\x12\x0e\n\x06\x62ucket\x18\x01 \x01(\t\x12\x0c\n\x04path\x18\x02 \x01(\t\"\xd0\x01\n\x06\x43hroot\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x11\n\tcache_dir\x18\x02 \x01(\t\x12)\n\x03\x65nv\x18\x03 \x01(\x0b\x32\x1c.chromiumos.Chroot.ChrootEnv\x12\x12\n\nchrome_dir\x18\x04 \x01(\t\x1aZ\n\tChrootEnv\x12&\n\tuse_flags\x18\x01 \x03(\x0b\x32\x13.chromiumos.UseFlag\x12%\n\x08\x66\x65\x61tures\x18\x02 \x03(\x0b\x32\x13.chromiumos.FeatureJ\x04\x08\x05\x10\x06R\x04goma\"\x1a\n\x07\x46\x65\x61ture\x12\x0f\n\x07\x66\x65\x61ture\x18\x01 \x01(\t\"B\n\x10RemoteexecConfig\x12\x14\n\x0creclient_dir\x18\x01 \x01(\t\x12\x18\n\x10reproxy_cfg_file\x18\x02 \x01(\t\"\xcf\x02\n\nGomaConfig\x12\x10\n\x08goma_dir\x18\x01 \x01(\t\x12\x18\n\x10goma_client_json\x18\x02 \x01(\t\x12\x19\n\x11\x63hromeos_goma_dir\x18\x03 \x01(\t\x12:\n\rgoma_approach\x18\x04 \x01(\x0e\x32#.chromiumos.GomaConfig.GomaApproach\x12&\n\x07log_dir\x18\x05 \x01(\x0b\x32\x15.chromiumos.SyncedDir\x12\x12\n\nstats_file\x18\x06 \x01(\t\x12\x15\n\rcounterz_file\x18\x07 \x01(\t\"k\n\x0cGomaApproach\x12\x1d\n\x19GOMA_APPROACH_UNSPECIFIED\x10\x00\x12\x0b\n\x07\x44\x45\x46\x41ULT\x10\x01\x12\x0c\n\x08RBE_PROD\x10\x02\x12\x0f\n\x0bRBE_STAGING\x10\x03\x12\x10\n\x0cRBE_CHROMEOS\x10\x04\"M\n\rGomaArtifacts\x12\x12\n\nstats_file\x18\x01 \x01(\t\x12\x15\n\rcounterz_file\x18\x02 \x01(\t\x12\x11\n\tlog_files\x18\x03 \x03(\t\"F\n\x0bPackageInfo\x12\x14\n\x0cpackage_name\x18\x01 \x01(\t\x12\x10\n\x08\x63\x61tegory\x18\x02 \x01(\t\x12\x0f\n\x07version\x18\x03 \x01(\t\"\x17\n\x07Profile\x12\x0c\n\x04name\x18\x01 \x01(\t\"\xa8\x01\n\x10PackageIndexInfo\x12\x14\n\x0csnapshot_sha\x18\x01 \x01(\t\x12\x17\n\x0fsnapshot_number\x18\x02 \x01(\x05\x12-\n\x0c\x62uild_target\x18\x03 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x10\n\x08location\x18\x04 \x01(\t\x12$\n\x07profile\x18\x05 \x01(\x0b\x32\x13.chromiumos.Profile\"w\n\x04Path\x12\x0c\n\x04path\x18\x01 \x01(\t\x12+\n\x08location\x18\x02 \x01(\x0e\x32\x19.chromiumos.Path.Location\"4\n\x08Location\x12\x0f\n\x0bNO_LOCATION\x10\x00\x12\n\n\x06INSIDE\x10\x01\x12\x0b\n\x07OUTSIDE\x10\x02\",\n\nResultPath\x12\x1e\n\x04path\x18\x01 \x01(\x0b\x32\x10.chromiumos.Path\"\x18\n\tSyncedDir\x12\x0b\n\x03\x64ir\x18\x01 \x01(\t\"O\n\x0cGerritChange\x12\x0c\n\x04host\x18\x01 \x01(\t\x12\x0f\n\x07project\x18\x02 \x01(\t\x12\x0e\n\x06\x63hange\x18\x03 \x01(\x03\x12\x10\n\x08patchset\x18\x04 \x01(\x03\"Y\n\rGitilesCommit\x12\x0c\n\x04host\x18\x01 \x01(\t\x12\x0f\n\x07project\x18\x02 \x01(\t\x12\n\n\x02id\x18\x03 \x01(\t\x12\x0b\n\x03ref\x18\x04 \x01(\t\x12\x10\n\x08position\x18\x05 \x01(\r\"\x17\n\x07UseFlag\x12\x0c\n\x04\x66lag\x18\x01 \x01(\t\"\xb8\x02\n\x0eReleaseBuilder\x12\x39\n\tmilestone\x18\x01 \x01(\x0b\x32$.chromiumos.ReleaseBuilder.MilestoneH\x00\x12\x16\n\x0e\x62uild_schedule\x18\x02 \x01(\t\x12\x38\n\x0f\x65xpiration_date\x18\x03 \x01(\x0b\x32\x1f.chromiumos.ReleaseBuilder.Date\x1a\x15\n\x04\x44\x61te\x12\r\n\x05value\x18\x01 \x01(\t\x1am\n\tMilestone\x12\x0e\n\x06number\x18\x01 \x01(\x05\x12;\n\x12target_branch_date\x18\x02 \x01(\x0b\x32\x1f.chromiumos.ReleaseBuilder.Date\x12\x13\n\x0b\x62ranch_name\x18\x03 \x01(\tB\x13\n\x11milestone_message\"?\n\x0fReleaseBuilders\x12,\n\x08\x62uilders\x18\x01 \x03(\x0b\x32\x1a.chromiumos.ReleaseBuilder\"\xf4\x01\n\x0fReleaseChannels\x12J\n\x10release_channels\x18\x01 \x03(\x0b\x32\x30.chromiumos.ReleaseChannels.ReleaseChannelsEntry\x1a\x34\n\x0b\x43hannelList\x12%\n\x08\x63hannels\x18\x01 \x03(\x0e\x32\x13.chromiumos.Channel\x1a_\n\x14ReleaseChannelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\x36\n\x05value\x18\x02 \x01(\x0b\x32\'.chromiumos.ReleaseChannels.ChannelList:\x02\x38\x01\"&\n\nProtoBytes\x12\x18\n\x10serialized_proto\x18\x01 \x01(\x0c\"q\n\x1dPrepareForBuildAdditionalArgs\x12\x1c\n\x12\x63hrome_cwp_profile\x18\x01 \x01(\tH\x00\x12\x18\n\x0ekernel_version\x18\x02 \x01(\tH\x00\x42\x18\n\x16prepare_for_build_args\"A\n\x0b\x41\x66\x64oRelease\x12\x1a\n\x12\x63hrome_cwp_profile\x18\x01 \x01(\t\x12\x16\n\x0eimage_build_id\x18\x02 \x01(\x03\"\x97\x01\n\x13\x41rtifactProfileInfo\x12\x1c\n\x12\x63hrome_cwp_profile\x18\x01 \x01(\tH\x00\x12\x18\n\x0ekernel_version\x18\x02 \x01(\tH\x00\x12/\n\x0c\x61\x66\x64o_release\x18\x03 \x01(\x0b\x32\x17.chromiumos.AfdoReleaseH\x00\x42\x17\n\x15\x61rtifact_profile_info\"\xb5&\n\x12\x41rtifactsByService\x12\x35\n\x06legacy\x18\x01 \x01(\x0b\x32%.chromiumos.ArtifactsByService.Legacy\x12;\n\ttoolchain\x18\x02 \x01(\x0b\x32(.chromiumos.ArtifactsByService.Toolchain\x12\x33\n\x05image\x18\x03 \x01(\x0b\x32$.chromiumos.ArtifactsByService.Image\x12\x37\n\x07package\x18\x04 \x01(\x0b\x32&.chromiumos.ArtifactsByService.Package\x12\x37\n\x07sysroot\x18\x05 \x01(\x0b\x32&.chromiumos.ArtifactsByService.Sysroot\x12\x31\n\x04test\x18\x06 \x01(\x0b\x32#.chromiumos.ArtifactsByService.Test\x12\x35\n\x0cprofile_info\x18\x07 \x01(\x0b\x32\x1f.chromiumos.ArtifactProfileInfo\x12\x39\n\x08\x66irmware\x18\x08 \x01(\x0b\x32\'.chromiumos.ArtifactsByService.Firmware\x12\x33\n\x05infra\x18\t \x01(\x0b\x32$.chromiumos.ArtifactsByService.Infra\x1a\xb0\x01\n\x16\x43odeCoverageUploadInfo\x12]\n\rcoverage_type\x18\x01 \x01(\x0e\x32\x46.chromiumos.ArtifactsByService.CodeCoverageUploadInfo.CodeCoverageType\"7\n\x10\x43odeCoverageType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x08\n\x04LLVM\x10\x01\x12\x08\n\x04LCOV\x10\x02\x1a\xec\x04\n\x06Legacy\x12K\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x32.chromiumos.ArtifactsByService.Legacy.ArtifactInfo\x12L\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x32.chromiumos.ArtifactsByService.Legacy.ArtifactInfo\x1a\x9c\x01\n\x0c\x41rtifactInfo\x12J\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x32.chromiumos.ArtifactsByService.Legacy.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\tJ\x04\x08\x03\x10\x04J\x04\x08\x05\x10\x06R\x0cprofile_info\"\xa7\x02\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\r\n\tIMAGE_ZIP\x10\x01\x12\x17\n\x13TEST_UPDATE_PAYLOAD\x10\x02\x12\x12\n\x0e\x41UTOTEST_FILES\x10\x03\x12\x0e\n\nTAST_FILES\x10\x04\x12\x17\n\x13PINNED_GUEST_IMAGES\x10\x05\x12\x0c\n\x08\x46IRMWARE\x10\x06\x12\x0f\n\x0b\x45\x42UILD_LOGS\x10\x07\x12\x13\n\x0f\x43HROMEOS_CONFIG\x10\x08\x12\x0e\n\nCPE_REPORT\x10\t\x12\x12\n\x0eIMAGE_ARCHIVES\x10\n\x12\x13\n\x0f\x46PMCU_UNITTESTS\x10\x1b\x12\x0f\n\x0bGCE_TARBALL\x10\x1c\x12\x11\n\rDEBUG_SYMBOLS\x10 \"\x04\x08\x0b\x10\x1a\"\x04\x08\x1d\x10\x1f\"\x04\x08!\x10+\x1a\xb9\x07\n\tToolchain\x12N\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x35.chromiumos.ArtifactsByService.Toolchain.ArtifactInfo\x12O\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x35.chromiumos.ArtifactsByService.Toolchain.ArtifactInfo\x1a\x8b\x01\n\x0c\x41rtifactInfo\x12M\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x35.chromiumos.ArtifactsByService.Toolchain.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\tJ\x04\x08\x05\x10\x06\"\xfc\x04\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12$\n UNVERIFIED_CHROME_LLVM_ORDERFILE\x10\x0b\x12\"\n\x1eVERIFIED_CHROME_LLVM_ORDERFILE\x10\x0c\x12\x1e\n\x1a\x43HROME_CLANG_WARNINGS_FILE\x10\r\x12\x1c\n\x18UNVERIFIED_LLVM_PGO_FILE\x10\x0e\x12)\n%UNVERIFIED_CHROME_BENCHMARK_AFDO_FILE\x10\x0f\x12\'\n#VERIFIED_CHROME_BENCHMARK_AFDO_FILE\x10\x10\x12!\n\x1dVERIFIED_KERNEL_CWP_AFDO_FILE\x10\x11\x12#\n\x1fUNVERIFIED_KERNEL_CWP_AFDO_FILE\x10\x12\x12#\n\x1fUNVERIFIED_CHROME_CWP_AFDO_FILE\x10\x13\x12!\n\x1dVERIFIED_CHROME_CWP_AFDO_FILE\x10\x14\x12\x1e\n\x1aVERIFIED_RELEASE_AFDO_FILE\x10\x15\x12)\n%UNVERIFIED_CHROME_BENCHMARK_PERF_FILE\x10\x16\x12\x17\n\x13\x43HROME_DEBUG_BINARY\x10\x17\x12\x1a\n\x16TOOLCHAIN_WARNING_LOGS\x10\x18\x12)\n%CHROME_AFDO_PROFILE_FOR_ANDROID_LINUX\x10\x19\x12\x19\n\x15\x43LANG_CRASH_DIAGNOSES\x10\x1a\x12\x17\n\x13\x43OMPILER_RUSAGE_LOG\x10\x1d\"\x04\x08\x01\x10\n\"\x04\x08\x1b\x10\x1c\"\x04\x08\x1e\x10+\x1a\x94\x03\n\x05Image\x12J\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x31.chromiumos.ArtifactsByService.Image.ArtifactInfo\x12K\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x31.chromiumos.ArtifactsByService.Image.ArtifactInfo\x1a\x87\x01\n\x0c\x41rtifactInfo\x12I\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x31.chromiumos.ArtifactsByService.Image.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\tJ\x04\x08\x05\x10\x06\"h\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\r\n\tDLC_IMAGE\x10\"\x12\x13\n\x0fLICENSE_CREDITS\x10&\x12\x11\n\rFACTORY_IMAGE\x10+\"\x04\x08\x01\x10!\"\x04\x08#\x10%\"\x04\x08\'\x10*\x1a\xd9\x02\n\x07Package\x12L\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x33.chromiumos.ArtifactsByService.Package.ArtifactInfo\x12M\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x33.chromiumos.ArtifactsByService.Package.ArtifactInfo\x1a\x89\x01\n\x0c\x41rtifactInfo\x12K\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x33.chromiumos.ArtifactsByService.Package.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\tJ\x04\x08\x05\x10\x06\"%\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\"\x04\x08\x01\x10+\x1a\xc7\x03\n\x07Sysroot\x12L\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x33.chromiumos.ArtifactsByService.Sysroot.ArtifactInfo\x12M\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x33.chromiumos.ArtifactsByService.Sysroot.ArtifactInfo\x1a\x89\x01\n\x0c\x41rtifactInfo\x12K\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x33.chromiumos.ArtifactsByService.Sysroot.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\tJ\x04\x08\x05\x10\x06\"\x92\x01\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x11\n\rDEBUG_SYMBOLS\x10 \x12\x1a\n\x16\x42REAKPAD_DEBUG_SYMBOLS\x10#\x12\x19\n\x15SIMPLE_CHROME_SYSROOT\x10(\x12\x15\n\x11\x43HROME_EBUILD_ENV\x10)\"\x04\x08\x01\x10\x1f\"\x04\x08!\x10\"\"\x04\x08$\x10\'\x1a\xec\x03\n\x04Test\x12I\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x30.chromiumos.ArtifactsByService.Test.ArtifactInfo\x12J\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x30.chromiumos.ArtifactsByService.Test.ArtifactInfo\x1a\xe0\x01\n\x0c\x41rtifactInfo\x12H\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x30.chromiumos.ArtifactsByService.Test.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\t\x12X\n\x19\x63ode_coverage_upload_info\x18\x06 \x01(\x0b\x32\x35.chromiumos.ArtifactsByService.CodeCoverageUploadInfoJ\x04\x08\x05\x10\x06\"j\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x0e\n\nUNIT_TESTS\x10%\x12\x1b\n\x17\x43ODE_COVERAGE_LLVM_JSON\x10\'\x12\n\n\x06HWQUAL\x10*\"\x04\x08\x01\x10$\"\x04\x08&\x10&\"\x04\x08(\x10)\x1a\xb1\x04\n\x08\x46irmware\x12M\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x34.chromiumos.ArtifactsByService.Firmware.ArtifactInfo\x12N\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x34.chromiumos.ArtifactsByService.Firmware.ArtifactInfo\x1a\x8e\x02\n\x0c\x41rtifactInfo\x12L\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x34.chromiumos.ArtifactsByService.Firmware.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\t\x12(\n\x08location\x18\x06 \x01(\x0e\x32\x16.chromiumos.FwLocation\x12X\n\x19\x63ode_coverage_upload_info\x18\x07 \x01(\x0b\x32\x35.chromiumos.ArtifactsByService.CodeCoverageUploadInfoJ\x04\x08\x05\x10\x06\"u\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x14\n\x10\x46IRMWARE_TARBALL\x10\x1e\x12\x19\n\x15\x46IRMWARE_TARBALL_INFO\x10\x1f\x12\x11\n\rFIRMWARE_LCOV\x10!\"\x04\x08\x01\x10\x1d\"\x04\x08 \x10 \"\x04\x08\"\x10+\x1a\xeb\x02\n\x05Infra\x12J\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x31.chromiumos.ArtifactsByService.Infra.ArtifactInfo\x12K\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x31.chromiumos.ArtifactsByService.Infra.ArtifactInfo\x1a\x87\x01\n\x0c\x41rtifactInfo\x12I\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x31.chromiumos.ArtifactsByService.Infra.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\tJ\x04\x08\x05\x10\x06\"?\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x12\n\x0e\x42UILD_MANIFEST\x10$\"\x04\x08\x01\x10#\"\x04\x08%\x10+\"\x8e\x12\n\x1aUploadedArtifactsByService\x12=\n\x06legacy\x18\x01 \x01(\x0b\x32-.chromiumos.UploadedArtifactsByService.Legacy\x12\x43\n\ttoolchain\x18\x02 \x01(\x0b\x32\x30.chromiumos.UploadedArtifactsByService.Toolchain\x12;\n\x05image\x18\x03 \x01(\x0b\x32,.chromiumos.UploadedArtifactsByService.Image\x12?\n\x07package\x18\x04 \x01(\x0b\x32..chromiumos.UploadedArtifactsByService.Package\x12?\n\x07sysroot\x18\x05 \x01(\x0b\x32..chromiumos.UploadedArtifactsByService.Sysroot\x12\x39\n\x04test\x18\x06 \x01(\x0b\x32+.chromiumos.UploadedArtifactsByService.Test\x12\x41\n\x08\x66irmware\x18\x07 \x01(\x0b\x32/.chromiumos.UploadedArtifactsByService.Firmware\x12;\n\x05infra\x18\x08 \x01(\x0b\x32,.chromiumos.UploadedArtifactsByService.Infra\x1a\xd5\x01\n\x06Legacy\x12N\n\tartifacts\x18\x01 \x03(\x0b\x32;.chromiumos.UploadedArtifactsByService.Legacy.ArtifactPaths\x1a{\n\rArtifactPaths\x12I\n\rartifact_type\x18\x01 \x01(\x0e\x32\x32.chromiumos.ArtifactsByService.Legacy.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path\x1a\xde\x01\n\tToolchain\x12Q\n\tartifacts\x18\x01 \x03(\x0b\x32>.chromiumos.UploadedArtifactsByService.Toolchain.ArtifactPaths\x1a~\n\rArtifactPaths\x12L\n\rartifact_type\x18\x01 \x01(\x0e\x32\x35.chromiumos.ArtifactsByService.Toolchain.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path\x1a\xd2\x01\n\x05Image\x12M\n\tartifacts\x18\x01 \x03(\x0b\x32:.chromiumos.UploadedArtifactsByService.Image.ArtifactPaths\x1az\n\rArtifactPaths\x12H\n\rartifact_type\x18\x01 \x01(\x0e\x32\x31.chromiumos.ArtifactsByService.Image.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path\x1a\xd8\x01\n\x07Package\x12O\n\tartifacts\x18\x01 \x03(\x0b\x32<.chromiumos.UploadedArtifactsByService.Package.ArtifactPaths\x1a|\n\rArtifactPaths\x12J\n\rartifact_type\x18\x01 \x01(\x0e\x32\x33.chromiumos.ArtifactsByService.Package.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path\x1a\xd8\x01\n\x07Sysroot\x12O\n\tartifacts\x18\x01 \x03(\x0b\x32<.chromiumos.UploadedArtifactsByService.Sysroot.ArtifactPaths\x1a|\n\rArtifactPaths\x12J\n\rartifact_type\x18\x01 \x01(\x0e\x32\x33.chromiumos.ArtifactsByService.Sysroot.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path\x1a\xcf\x01\n\x04Test\x12L\n\tartifacts\x18\x01 \x03(\x0b\x32\x39.chromiumos.UploadedArtifactsByService.Test.ArtifactPaths\x1ay\n\rArtifactPaths\x12G\n\rartifact_type\x18\x01 \x01(\x0e\x32\x30.chromiumos.ArtifactsByService.Test.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path\x1a\x86\x02\n\x08\x46irmware\x12P\n\tartifacts\x18\x01 \x03(\x0b\x32=.chromiumos.UploadedArtifactsByService.Firmware.ArtifactPaths\x1a\xa7\x01\n\rArtifactPaths\x12K\n\rartifact_type\x18\x01 \x01(\x0e\x32\x34.chromiumos.ArtifactsByService.Firmware.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path\x12(\n\x08location\x18\x03 \x01(\x0e\x32\x16.chromiumos.FwLocation\x1a\xd2\x01\n\x05Infra\x12M\n\tartifacts\x18\x01 \x03(\x0b\x32:.chromiumos.UploadedArtifactsByService.Infra.ArtifactPaths\x1az\n\rArtifactPaths\x12H\n\rartifact_type\x18\x01 \x01(\x0e\x32\x31.chromiumos.ArtifactsByService.Infra.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path*\xf5\x04\n\tImageType\x12\x18\n\x14IMAGE_TYPE_UNDEFINED\x10\x00\x12\x13\n\x0fIMAGE_TYPE_BASE\x10\x01\x12\x12\n\x0eIMAGE_TYPE_DEV\x10\x02\x12\x13\n\x0fIMAGE_TYPE_TEST\x10\x03\x12\x16\n\x12IMAGE_TYPE_BASE_VM\x10\x04\x12\x16\n\x12IMAGE_TYPE_TEST_VM\x10\x05\x12\x17\n\x13IMAGE_TYPE_RECOVERY\x10\x06\x12\x16\n\x12IMAGE_TYPE_FACTORY\x10\x07\x12\x17\n\x13IMAGE_TYPE_FIRMWARE\x10\x08\x12\x1c\n\x18IMAGE_TYPE_CR50_FIRMWARE\x10\t\x12\x1c\n\x18IMAGE_TYPE_BASE_GUEST_VM\x10\n\x12\x1c\n\x18IMAGE_TYPE_TEST_GUEST_VM\x10\x0b\x12\x12\n\x0eIMAGE_TYPE_DLC\x10\x0c\x12\x1b\n\x17IMAGE_TYPE_GSC_FIRMWARE\x10\r\x12\x1e\n\x1aIMAGE_TYPE_ACCESSORY_USBPD\x10\x0e\x12\x1e\n\x1aIMAGE_TYPE_ACCESSORY_RWSIG\x10\x0f\x12\x1b\n\x17IMAGE_TYPE_HPS_FIRMWARE\x10\x10*\x04\x42\x41SE*\x04TEST*\x03\x44\x45V*\x07\x42\x41SE_VM*\x07TEST_VM*\x08RECOVERY*\x07\x46\x41\x43TORY*\x08\x46IRMWARE*\rCR50_FIRMWARE*\rBASE_GUEST_VM*\rTEST_GUEST_VM*\x03\x44LC*\x0cGSC_FIRMWARE*\x0f\x41\x43\x43\x45SSORY_USBPD*\x0f\x41\x43\x43\x45SSORY_RWSIG*\x0cHPS_FIRMWARE*\x80\x01\n\x07\x43hannel\x12\x17\n\x13\x43HANNEL_UNSPECIFIED\x10\x00\x12\x12\n\x0e\x43HANNEL_STABLE\x10\x01\x12\x10\n\x0c\x43HANNEL_BETA\x10\x02\x12\x0f\n\x0b\x43HANNEL_DEV\x10\x03\x12\x12\n\x0e\x43HANNEL_CANARY\x10\x04\x12\x11\n\rCHANNEL_RUBIK\x10\x05*l\n\tDeltaType\x12\x11\n\rDELTA_UNKNOWN\x10\x00\x12\x0c\n\x08NO_DELTA\x10\x01\x12\x07\n\x03\x46SI\x10\x02\x12\r\n\tMILESTONE\x10\x03\x12\t\n\x05OMAHA\x10\x04\x12\x12\n\x0eSTEPPING_STONE\x10\x05\x12\x07\n\x03N2N\x10\x06*q\n\nFwLocation\x12\x17\n\x13\x46W_LOCATION_UNKNOWN\x10\x00\x12\x0f\n\x0bPLATFORM_EC\x10\x01\x12\x13\n\x0fPLATFORM_ZEPHYR\x10\x02\x12\x11\n\rPLATFORM_TI50\x10\x03\x12\x11\n\rPLATFORM_CR50\x10\x04\x42Y\n!com.google.chrome.crosinfra.protoZ4go.chromium.org/chromiumos/infra/proto/go/chromiumosb\x06proto3'
 )
 
 _IMAGETYPE = _descriptor.EnumDescriptor(
@@ -110,11 +110,16 @@
       serialized_options=None,
       type=None,
       create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='IMAGE_TYPE_HPS_FIRMWARE', index=16, number=16,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=10317,
-  serialized_end=10903,
+  serialized_start=9736,
+  serialized_end=10365,
 )
 _sym_db.RegisterEnumDescriptor(_IMAGETYPE)
 
@@ -159,8 +164,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=10906,
-  serialized_end=11034,
+  serialized_start=10368,
+  serialized_end=10496,
 )
 _sym_db.RegisterEnumDescriptor(_CHANNEL)
 
@@ -210,8 +215,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=11036,
-  serialized_end=11144,
+  serialized_start=10498,
+  serialized_end=10606,
 )
 _sym_db.RegisterEnumDescriptor(_DELTATYPE)
 
@@ -243,56 +248,20 @@
       serialized_options=None,
       type=None,
       create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='PLATFORM_CR50', index=4, number=4,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=11146,
-  serialized_end=11240,
+  serialized_start=10608,
+  serialized_end=10721,
 )
 _sym_db.RegisterEnumDescriptor(_FWLOCATION)
 
 FwLocation = enum_type_wrapper.EnumTypeWrapper(_FWLOCATION)
-_AFDOARTIFACTTYPE = _descriptor.EnumDescriptor(
-  name='AFDOArtifactType',
-  full_name='chromiumos.AFDOArtifactType',
-  filename=None,
-  file=DESCRIPTOR,
-  create_key=_descriptor._internal_create_key,
-  values=[
-    _descriptor.EnumValueDescriptor(
-      name='NONE_TYPE', index=0, number=0,
-      serialized_options=None,
-      type=None,
-      create_key=_descriptor._internal_create_key),
-    _descriptor.EnumValueDescriptor(
-      name='ORDERFILE', index=1, number=1,
-      serialized_options=None,
-      type=None,
-      create_key=_descriptor._internal_create_key),
-    _descriptor.EnumValueDescriptor(
-      name='BENCHMARK_AFDO', index=2, number=2,
-      serialized_options=None,
-      type=None,
-      create_key=_descriptor._internal_create_key),
-    _descriptor.EnumValueDescriptor(
-      name='KERNEL_AFDO', index=3, number=3,
-      serialized_options=None,
-      type=None,
-      create_key=_descriptor._internal_create_key),
-    _descriptor.EnumValueDescriptor(
-      name='CHROME_AFDO', index=4, number=4,
-      serialized_options=None,
-      type=None,
-      create_key=_descriptor._internal_create_key),
-  ],
-  containing_type=None,
-  serialized_options=None,
-  serialized_start=11242,
-  serialized_end=11344,
-)
-_sym_db.RegisterEnumDescriptor(_AFDOARTIFACTTYPE)
-
-AFDOArtifactType = enum_type_wrapper.EnumTypeWrapper(_AFDOARTIFACTTYPE)
 IMAGE_TYPE_UNDEFINED = 0
 IMAGE_TYPE_BASE = 1
 IMAGE_TYPE_DEV = 2
@@ -309,6 +278,7 @@
 IMAGE_TYPE_GSC_FIRMWARE = 13
 IMAGE_TYPE_ACCESSORY_USBPD = 14
 IMAGE_TYPE_ACCESSORY_RWSIG = 15
+IMAGE_TYPE_HPS_FIRMWARE = 16
 CHANNEL_UNSPECIFIED = 0
 CHANNEL_STABLE = 1
 CHANNEL_BETA = 2
@@ -326,11 +296,7 @@
 PLATFORM_EC = 1
 PLATFORM_ZEPHYR = 2
 PLATFORM_TI50 = 3
-NONE_TYPE = 0
-ORDERFILE = 1
-BENCHMARK_AFDO = 2
-KERNEL_AFDO = 3
-CHROME_AFDO = 4
+PLATFORM_CR50 = 4
 
 
 _GOMACONFIG_GOMAAPPROACH = _descriptor.EnumDescriptor(
@@ -368,8 +334,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=577,
-  serialized_end=684,
+  serialized_start=645,
+  serialized_end=752,
 )
 _sym_db.RegisterEnumDescriptor(_GOMACONFIG_GOMAAPPROACH)
 
@@ -398,8 +364,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1100,
-  serialized_end=1152,
+  serialized_start=1168,
+  serialized_end=1220,
 )
 _sym_db.RegisterEnumDescriptor(_PATH_LOCATION)
 
@@ -428,8 +394,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=3072,
-  serialized_end=3127,
+  serialized_start=3140,
+  serialized_end=3195,
 )
 _sym_db.RegisterEnumDescriptor(_ARTIFACTSBYSERVICE_CODECOVERAGEUPLOADINFO_CODECOVERAGETYPE)
 
@@ -513,8 +479,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=3525,
-  serialized_end=3820,
+  serialized_start=3523,
+  serialized_end=3818,
 )
 _sym_db.RegisterEnumDescriptor(_ARTIFACTSBYSERVICE_LEGACY_ARTIFACTTYPE)
 
@@ -618,8 +584,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=4210,
-  serialized_end=4846,
+  serialized_start=4138,
+  serialized_end=4774,
 )
 _sym_db.RegisterEnumDescriptor(_ARTIFACTSBYSERVICE_TOOLCHAIN_ARTIFACTTYPE)
 
@@ -653,8 +619,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=5219,
-  serialized_end=5323,
+  serialized_start=5077,
+  serialized_end=5181,
 )
 _sym_db.RegisterEnumDescriptor(_ARTIFACTSBYSERVICE_IMAGE_ARTIFACTTYPE)
 
@@ -673,8 +639,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=5704,
-  serialized_end=5741,
+  serialized_start=5492,
+  serialized_end=5529,
 )
 _sym_db.RegisterEnumDescriptor(_ARTIFACTSBYSERVICE_PACKAGE_ARTIFACTTYPE)
 
@@ -713,8 +679,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=6123,
-  serialized_end=6269,
+  serialized_start=5841,
+  serialized_end=5987,
 )
 _sym_db.RegisterEnumDescriptor(_ARTIFACTSBYSERVICE_SYSROOT_ARTIFACTTYPE)
 
@@ -748,8 +714,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=6728,
-  serialized_end=6834,
+  serialized_start=6376,
+  serialized_end=6482,
 )
 _sym_db.RegisterEnumDescriptor(_ARTIFACTSBYSERVICE_TEST_ARTIFACTTYPE)
 
@@ -783,8 +749,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=7351,
-  serialized_end=7468,
+  serialized_start=6929,
+  serialized_end=7046,
 )
 _sym_db.RegisterEnumDescriptor(_ARTIFACTSBYSERVICE_FIRMWARE_ARTIFACTTYPE)
 
@@ -808,41 +774,11 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=7841,
-  serialized_end=7904,
+  serialized_start=7349,
+  serialized_end=7412,
 )
 _sym_db.RegisterEnumDescriptor(_ARTIFACTSBYSERVICE_INFRA_ARTIFACTTYPE)
 
-_ARTIFACTSBYSERVICE_PUBLISHCONDITION = _descriptor.EnumDescriptor(
-  name='PublishCondition',
-  full_name='chromiumos.ArtifactsByService.PublishCondition',
-  filename=None,
-  file=DESCRIPTOR,
-  create_key=_descriptor._internal_create_key,
-  values=[
-    _descriptor.EnumValueDescriptor(
-      name='PUBLISH_UNSPECIFIED', index=0, number=0,
-      serialized_options=None,
-      type=None,
-      create_key=_descriptor._internal_create_key),
-    _descriptor.EnumValueDescriptor(
-      name='PUBLISH_ON_SUCCESS', index=1, number=1,
-      serialized_options=None,
-      type=None,
-      create_key=_descriptor._internal_create_key),
-    _descriptor.EnumValueDescriptor(
-      name='PUBLISH_ALWAYS', index=2, number=2,
-      serialized_options=None,
-      type=None,
-      create_key=_descriptor._internal_create_key),
-  ],
-  containing_type=None,
-  serialized_options=None,
-  serialized_start=7906,
-  serialized_end=7993,
-)
-_sym_db.RegisterEnumDescriptor(_ARTIFACTSBYSERVICE_PUBLISHCONDITION)
-
 
 _BUILDTARGET = _descriptor.Descriptor(
   name='BuildTarget',
@@ -1038,6 +974,45 @@
 )
 
 
+_REMOTEEXECCONFIG = _descriptor.Descriptor(
+  name='RemoteexecConfig',
+  full_name='chromiumos.RemoteexecConfig',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='reclient_dir', full_name='chromiumos.RemoteexecConfig.reclient_dir', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='reproxy_cfg_file', full_name='chromiumos.RemoteexecConfig.reproxy_cfg_file', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=348,
+  serialized_end=414,
+)
+
+
 _GOMACONFIG = _descriptor.Descriptor(
   name='GomaConfig',
   full_name='chromiumos.GomaConfig',
@@ -1108,8 +1083,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=349,
-  serialized_end=684,
+  serialized_start=417,
+  serialized_end=752,
 )
 
 
@@ -1154,8 +1129,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=686,
-  serialized_end=763,
+  serialized_start=754,
+  serialized_end=831,
 )
 
 
@@ -1200,8 +1175,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=765,
-  serialized_end=835,
+  serialized_start=833,
+  serialized_end=903,
 )
 
 
@@ -1232,8 +1207,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=837,
-  serialized_end=860,
+  serialized_start=905,
+  serialized_end=928,
 )
 
 
@@ -1292,8 +1267,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=863,
-  serialized_end=1031,
+  serialized_start=931,
+  serialized_end=1099,
 )
 
 
@@ -1332,8 +1307,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1033,
-  serialized_end=1152,
+  serialized_start=1101,
+  serialized_end=1220,
 )
 
 
@@ -1364,8 +1339,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1154,
-  serialized_end=1198,
+  serialized_start=1222,
+  serialized_end=1266,
 )
 
 
@@ -1396,8 +1371,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1200,
-  serialized_end=1224,
+  serialized_start=1268,
+  serialized_end=1292,
 )
 
 
@@ -1449,8 +1424,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1226,
-  serialized_end=1305,
+  serialized_start=1294,
+  serialized_end=1373,
 )
 
 
@@ -1509,8 +1484,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1307,
-  serialized_end=1396,
+  serialized_start=1375,
+  serialized_end=1464,
 )
 
 
@@ -1541,8 +1516,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1398,
-  serialized_end=1421,
+  serialized_start=1466,
+  serialized_end=1489,
 )
 
 
@@ -1573,8 +1548,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1583,
-  serialized_end=1604,
+  serialized_start=1651,
+  serialized_end=1672,
 )
 
 _RELEASEBUILDER_MILESTONE = _descriptor.Descriptor(
@@ -1618,8 +1593,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1606,
-  serialized_end=1715,
+  serialized_start=1674,
+  serialized_end=1783,
 )
 
 _RELEASEBUILDER = _descriptor.Descriptor(
@@ -1668,8 +1643,8 @@
       create_key=_descriptor._internal_create_key,
     fields=[]),
   ],
-  serialized_start=1424,
-  serialized_end=1736,
+  serialized_start=1492,
+  serialized_end=1804,
 )
 
 
@@ -1700,8 +1675,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1738,
-  serialized_end=1801,
+  serialized_start=1806,
+  serialized_end=1869,
 )
 
 
@@ -1732,8 +1707,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1899,
-  serialized_end=1951,
+  serialized_start=1967,
+  serialized_end=2019,
 )
 
 _RELEASECHANNELS_RELEASECHANNELSENTRY = _descriptor.Descriptor(
@@ -1770,8 +1745,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1953,
-  serialized_end=2048,
+  serialized_start=2021,
+  serialized_end=2116,
 )
 
 _RELEASECHANNELS = _descriptor.Descriptor(
@@ -1801,8 +1776,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1804,
-  serialized_end=2048,
+  serialized_start=1872,
+  serialized_end=2116,
 )
 
 
@@ -1833,8 +1808,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2050,
-  serialized_end=2088,
+  serialized_start=2118,
+  serialized_end=2156,
 )
 
 
@@ -1877,8 +1852,8 @@
       create_key=_descriptor._internal_create_key,
     fields=[]),
   ],
-  serialized_start=2090,
-  serialized_end=2203,
+  serialized_start=2158,
+  serialized_end=2271,
 )
 
 
@@ -1916,8 +1891,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2205,
-  serialized_end=2270,
+  serialized_start=2273,
+  serialized_end=2338,
 )
 
 
@@ -1967,8 +1942,8 @@
       create_key=_descriptor._internal_create_key,
     fields=[]),
   ],
-  serialized_start=2273,
-  serialized_end=2424,
+  serialized_start=2341,
+  serialized_end=2492,
 )
 
 
@@ -2000,8 +1975,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2951,
-  serialized_end=3127,
+  serialized_start=3019,
+  serialized_end=3195,
 )
 
 _ARTIFACTSBYSERVICE_LEGACY_ARTIFACTINFO = _descriptor.Descriptor(
@@ -2033,13 +2008,6 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='publish_condition', full_name='chromiumos.ArtifactsByService.Legacy.ArtifactInfo.publish_condition', index=3,
-      number=5, type=14, cpp_type=8, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -2052,8 +2020,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3296,
-  serialized_end=3522,
+  serialized_start=3364,
+  serialized_end=3520,
 )
 
 _ARTIFACTSBYSERVICE_LEGACY = _descriptor.Descriptor(
@@ -2091,8 +2059,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3130,
-  serialized_end=3820,
+  serialized_start=3198,
+  serialized_end=3818,
 )
 
 _ARTIFACTSBYSERVICE_TOOLCHAIN_ARTIFACTINFO = _descriptor.Descriptor(
@@ -2124,13 +2092,6 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='publish_condition', full_name='chromiumos.ArtifactsByService.Toolchain.ArtifactInfo.publish_condition', index=3,
-      number=5, type=14, cpp_type=8, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -2143,8 +2104,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3998,
-  serialized_end=4207,
+  serialized_start=3996,
+  serialized_end=4135,
 )
 
 _ARTIFACTSBYSERVICE_TOOLCHAIN = _descriptor.Descriptor(
@@ -2182,8 +2143,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3823,
-  serialized_end=4846,
+  serialized_start=3821,
+  serialized_end=4774,
 )
 
 _ARTIFACTSBYSERVICE_IMAGE_ARTIFACTINFO = _descriptor.Descriptor(
@@ -2215,13 +2176,6 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='publish_condition', full_name='chromiumos.ArtifactsByService.Image.ArtifactInfo.publish_condition', index=3,
-      number=5, type=14, cpp_type=8, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -2234,8 +2188,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5012,
-  serialized_end=5217,
+  serialized_start=4940,
+  serialized_end=5075,
 )
 
 _ARTIFACTSBYSERVICE_IMAGE = _descriptor.Descriptor(
@@ -2273,8 +2227,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4849,
-  serialized_end=5323,
+  serialized_start=4777,
+  serialized_end=5181,
 )
 
 _ARTIFACTSBYSERVICE_PACKAGE_ARTIFACTINFO = _descriptor.Descriptor(
@@ -2306,13 +2260,6 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='publish_condition', full_name='chromiumos.ArtifactsByService.Package.ArtifactInfo.publish_condition', index=3,
-      number=5, type=14, cpp_type=8, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -2325,8 +2272,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5495,
-  serialized_end=5702,
+  serialized_start=5353,
+  serialized_end=5490,
 )
 
 _ARTIFACTSBYSERVICE_PACKAGE = _descriptor.Descriptor(
@@ -2364,8 +2311,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5326,
-  serialized_end=5741,
+  serialized_start=5184,
+  serialized_end=5529,
 )
 
 _ARTIFACTSBYSERVICE_SYSROOT_ARTIFACTINFO = _descriptor.Descriptor(
@@ -2397,13 +2344,6 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='publish_condition', full_name='chromiumos.ArtifactsByService.Sysroot.ArtifactInfo.publish_condition', index=3,
-      number=5, type=14, cpp_type=8, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -2416,8 +2356,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5913,
-  serialized_end=6120,
+  serialized_start=5701,
+  serialized_end=5838,
 )
 
 _ARTIFACTSBYSERVICE_SYSROOT = _descriptor.Descriptor(
@@ -2455,8 +2395,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5744,
-  serialized_end=6269,
+  serialized_start=5532,
+  serialized_end=5987,
 )
 
 _ARTIFACTSBYSERVICE_TEST_ARTIFACTINFO = _descriptor.Descriptor(
@@ -2489,14 +2429,7 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='publish_condition', full_name='chromiumos.ArtifactsByService.Test.ArtifactInfo.publish_condition', index=3,
-      number=5, type=14, cpp_type=8, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='code_coverage_upload_info', full_name='chromiumos.ArtifactsByService.Test.ArtifactInfo.code_coverage_upload_info', index=4,
+      name='code_coverage_upload_info', full_name='chromiumos.ArtifactsByService.Test.ArtifactInfo.code_coverage_upload_info', index=3,
       number=6, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
@@ -2514,8 +2447,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=6432,
-  serialized_end=6726,
+  serialized_start=6150,
+  serialized_end=6374,
 )
 
 _ARTIFACTSBYSERVICE_TEST = _descriptor.Descriptor(
@@ -2553,8 +2486,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=6272,
-  serialized_end=6834,
+  serialized_start=5990,
+  serialized_end=6482,
 )
 
 _ARTIFACTSBYSERVICE_FIRMWARE_ARTIFACTINFO = _descriptor.Descriptor(
@@ -2587,21 +2520,14 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='publish_condition', full_name='chromiumos.ArtifactsByService.Firmware.ArtifactInfo.publish_condition', index=3,
-      number=5, type=14, cpp_type=8, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='location', full_name='chromiumos.ArtifactsByService.Firmware.ArtifactInfo.location', index=4,
+      name='location', full_name='chromiumos.ArtifactsByService.Firmware.ArtifactInfo.location', index=3,
       number=6, type=14, cpp_type=8, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='code_coverage_upload_info', full_name='chromiumos.ArtifactsByService.Firmware.ArtifactInfo.code_coverage_upload_info', index=5,
+      name='code_coverage_upload_info', full_name='chromiumos.ArtifactsByService.Firmware.ArtifactInfo.code_coverage_upload_info', index=4,
       number=7, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
@@ -2619,8 +2545,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=7009,
-  serialized_end=7349,
+  serialized_start=6657,
+  serialized_end=6927,
 )
 
 _ARTIFACTSBYSERVICE_FIRMWARE = _descriptor.Descriptor(
@@ -2658,8 +2584,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=6837,
-  serialized_end=7468,
+  serialized_start=6485,
+  serialized_end=7046,
 )
 
 _ARTIFACTSBYSERVICE_INFRA_ARTIFACTINFO = _descriptor.Descriptor(
@@ -2691,13 +2617,6 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='publish_condition', full_name='chromiumos.ArtifactsByService.Infra.ArtifactInfo.publish_condition', index=3,
-      number=5, type=14, cpp_type=8, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -2710,8 +2629,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=7634,
-  serialized_end=7839,
+  serialized_start=7212,
+  serialized_end=7347,
 )
 
 _ARTIFACTSBYSERVICE_INFRA = _descriptor.Descriptor(
@@ -2749,8 +2668,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=7471,
-  serialized_end=7904,
+  serialized_start=7049,
+  serialized_end=7412,
 )
 
 _ARTIFACTSBYSERVICE = _descriptor.Descriptor(
@@ -2829,7 +2748,6 @@
   ],
   nested_types=[_ARTIFACTSBYSERVICE_CODECOVERAGEUPLOADINFO, _ARTIFACTSBYSERVICE_LEGACY, _ARTIFACTSBYSERVICE_TOOLCHAIN, _ARTIFACTSBYSERVICE_IMAGE, _ARTIFACTSBYSERVICE_PACKAGE, _ARTIFACTSBYSERVICE_SYSROOT, _ARTIFACTSBYSERVICE_TEST, _ARTIFACTSBYSERVICE_FIRMWARE, _ARTIFACTSBYSERVICE_INFRA, ],
   enum_types=[
-    _ARTIFACTSBYSERVICE_PUBLISHCONDITION,
   ],
   serialized_options=None,
   is_extendable=False,
@@ -2837,8 +2755,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2427,
-  serialized_end=7993,
+  serialized_start=2495,
+  serialized_end=7412,
 )
 
 
@@ -2876,8 +2794,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=8627,
-  serialized_end=8750,
+  serialized_start=8046,
+  serialized_end=8169,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_LEGACY = _descriptor.Descriptor(
@@ -2907,8 +2825,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=8537,
-  serialized_end=8750,
+  serialized_start=7956,
+  serialized_end=8169,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_TOOLCHAIN_ARTIFACTPATHS = _descriptor.Descriptor(
@@ -2945,8 +2863,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=8849,
-  serialized_end=8975,
+  serialized_start=8268,
+  serialized_end=8394,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_TOOLCHAIN = _descriptor.Descriptor(
@@ -2976,8 +2894,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=8753,
-  serialized_end=8975,
+  serialized_start=8172,
+  serialized_end=8394,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_IMAGE_ARTIFACTPATHS = _descriptor.Descriptor(
@@ -3014,8 +2932,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9066,
-  serialized_end=9188,
+  serialized_start=8485,
+  serialized_end=8607,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_IMAGE = _descriptor.Descriptor(
@@ -3045,8 +2963,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=8978,
-  serialized_end=9188,
+  serialized_start=8397,
+  serialized_end=8607,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_PACKAGE_ARTIFACTPATHS = _descriptor.Descriptor(
@@ -3083,8 +3001,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9283,
-  serialized_end=9407,
+  serialized_start=8702,
+  serialized_end=8826,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_PACKAGE = _descriptor.Descriptor(
@@ -3114,8 +3032,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9191,
-  serialized_end=9407,
+  serialized_start=8610,
+  serialized_end=8826,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_SYSROOT_ARTIFACTPATHS = _descriptor.Descriptor(
@@ -3152,8 +3070,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9502,
-  serialized_end=9626,
+  serialized_start=8921,
+  serialized_end=9045,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_SYSROOT = _descriptor.Descriptor(
@@ -3183,8 +3101,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9410,
-  serialized_end=9626,
+  serialized_start=8829,
+  serialized_end=9045,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_TEST_ARTIFACTPATHS = _descriptor.Descriptor(
@@ -3221,8 +3139,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9715,
-  serialized_end=9836,
+  serialized_start=9134,
+  serialized_end=9255,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_TEST = _descriptor.Descriptor(
@@ -3252,8 +3170,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9629,
-  serialized_end=9836,
+  serialized_start=9048,
+  serialized_end=9255,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_FIRMWARE_ARTIFACTPATHS = _descriptor.Descriptor(
@@ -3297,8 +3215,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9934,
-  serialized_end=10101,
+  serialized_start=9353,
+  serialized_end=9520,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_FIRMWARE = _descriptor.Descriptor(
@@ -3328,8 +3246,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9839,
-  serialized_end=10101,
+  serialized_start=9258,
+  serialized_end=9520,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_INFRA_ARTIFACTPATHS = _descriptor.Descriptor(
@@ -3366,8 +3284,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=10192,
-  serialized_end=10314,
+  serialized_start=9611,
+  serialized_end=9733,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_INFRA = _descriptor.Descriptor(
@@ -3397,8 +3315,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=10104,
-  serialized_end=10314,
+  serialized_start=9523,
+  serialized_end=9733,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE = _descriptor.Descriptor(
@@ -3477,8 +3395,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=7996,
-  serialized_end=10314,
+  serialized_start=7415,
+  serialized_end=9733,
 )
 
 _CHROOT_CHROOTENV.fields_by_name['use_flags'].message_type = _USEFLAG
@@ -3527,42 +3445,36 @@
 _ARTIFACTSBYSERVICE_CODECOVERAGEUPLOADINFO.containing_type = _ARTIFACTSBYSERVICE
 _ARTIFACTSBYSERVICE_CODECOVERAGEUPLOADINFO_CODECOVERAGETYPE.containing_type = _ARTIFACTSBYSERVICE_CODECOVERAGEUPLOADINFO
 _ARTIFACTSBYSERVICE_LEGACY_ARTIFACTINFO.fields_by_name['artifact_types'].enum_type = _ARTIFACTSBYSERVICE_LEGACY_ARTIFACTTYPE
-_ARTIFACTSBYSERVICE_LEGACY_ARTIFACTINFO.fields_by_name['publish_condition'].enum_type = _ARTIFACTSBYSERVICE_PUBLISHCONDITION
 _ARTIFACTSBYSERVICE_LEGACY_ARTIFACTINFO.containing_type = _ARTIFACTSBYSERVICE_LEGACY
 _ARTIFACTSBYSERVICE_LEGACY.fields_by_name['input_artifacts'].message_type = _ARTIFACTSBYSERVICE_LEGACY_ARTIFACTINFO
 _ARTIFACTSBYSERVICE_LEGACY.fields_by_name['output_artifacts'].message_type = _ARTIFACTSBYSERVICE_LEGACY_ARTIFACTINFO
 _ARTIFACTSBYSERVICE_LEGACY.containing_type = _ARTIFACTSBYSERVICE
 _ARTIFACTSBYSERVICE_LEGACY_ARTIFACTTYPE.containing_type = _ARTIFACTSBYSERVICE_LEGACY
 _ARTIFACTSBYSERVICE_TOOLCHAIN_ARTIFACTINFO.fields_by_name['artifact_types'].enum_type = _ARTIFACTSBYSERVICE_TOOLCHAIN_ARTIFACTTYPE
-_ARTIFACTSBYSERVICE_TOOLCHAIN_ARTIFACTINFO.fields_by_name['publish_condition'].enum_type = _ARTIFACTSBYSERVICE_PUBLISHCONDITION
 _ARTIFACTSBYSERVICE_TOOLCHAIN_ARTIFACTINFO.containing_type = _ARTIFACTSBYSERVICE_TOOLCHAIN
 _ARTIFACTSBYSERVICE_TOOLCHAIN.fields_by_name['input_artifacts'].message_type = _ARTIFACTSBYSERVICE_TOOLCHAIN_ARTIFACTINFO
 _ARTIFACTSBYSERVICE_TOOLCHAIN.fields_by_name['output_artifacts'].message_type = _ARTIFACTSBYSERVICE_TOOLCHAIN_ARTIFACTINFO
 _ARTIFACTSBYSERVICE_TOOLCHAIN.containing_type = _ARTIFACTSBYSERVICE
 _ARTIFACTSBYSERVICE_TOOLCHAIN_ARTIFACTTYPE.containing_type = _ARTIFACTSBYSERVICE_TOOLCHAIN
 _ARTIFACTSBYSERVICE_IMAGE_ARTIFACTINFO.fields_by_name['artifact_types'].enum_type = _ARTIFACTSBYSERVICE_IMAGE_ARTIFACTTYPE
-_ARTIFACTSBYSERVICE_IMAGE_ARTIFACTINFO.fields_by_name['publish_condition'].enum_type = _ARTIFACTSBYSERVICE_PUBLISHCONDITION
 _ARTIFACTSBYSERVICE_IMAGE_ARTIFACTINFO.containing_type = _ARTIFACTSBYSERVICE_IMAGE
 _ARTIFACTSBYSERVICE_IMAGE.fields_by_name['input_artifacts'].message_type = _ARTIFACTSBYSERVICE_IMAGE_ARTIFACTINFO
 _ARTIFACTSBYSERVICE_IMAGE.fields_by_name['output_artifacts'].message_type = _ARTIFACTSBYSERVICE_IMAGE_ARTIFACTINFO
 _ARTIFACTSBYSERVICE_IMAGE.containing_type = _ARTIFACTSBYSERVICE
 _ARTIFACTSBYSERVICE_IMAGE_ARTIFACTTYPE.containing_type = _ARTIFACTSBYSERVICE_IMAGE
 _ARTIFACTSBYSERVICE_PACKAGE_ARTIFACTINFO.fields_by_name['artifact_types'].enum_type = _ARTIFACTSBYSERVICE_PACKAGE_ARTIFACTTYPE
-_ARTIFACTSBYSERVICE_PACKAGE_ARTIFACTINFO.fields_by_name['publish_condition'].enum_type = _ARTIFACTSBYSERVICE_PUBLISHCONDITION
 _ARTIFACTSBYSERVICE_PACKAGE_ARTIFACTINFO.containing_type = _ARTIFACTSBYSERVICE_PACKAGE
 _ARTIFACTSBYSERVICE_PACKAGE.fields_by_name['input_artifacts'].message_type = _ARTIFACTSBYSERVICE_PACKAGE_ARTIFACTINFO
 _ARTIFACTSBYSERVICE_PACKAGE.fields_by_name['output_artifacts'].message_type = _ARTIFACTSBYSERVICE_PACKAGE_ARTIFACTINFO
 _ARTIFACTSBYSERVICE_PACKAGE.containing_type = _ARTIFACTSBYSERVICE
 _ARTIFACTSBYSERVICE_PACKAGE_ARTIFACTTYPE.containing_type = _ARTIFACTSBYSERVICE_PACKAGE
 _ARTIFACTSBYSERVICE_SYSROOT_ARTIFACTINFO.fields_by_name['artifact_types'].enum_type = _ARTIFACTSBYSERVICE_SYSROOT_ARTIFACTTYPE
-_ARTIFACTSBYSERVICE_SYSROOT_ARTIFACTINFO.fields_by_name['publish_condition'].enum_type = _ARTIFACTSBYSERVICE_PUBLISHCONDITION
 _ARTIFACTSBYSERVICE_SYSROOT_ARTIFACTINFO.containing_type = _ARTIFACTSBYSERVICE_SYSROOT
 _ARTIFACTSBYSERVICE_SYSROOT.fields_by_name['input_artifacts'].message_type = _ARTIFACTSBYSERVICE_SYSROOT_ARTIFACTINFO
 _ARTIFACTSBYSERVICE_SYSROOT.fields_by_name['output_artifacts'].message_type = _ARTIFACTSBYSERVICE_SYSROOT_ARTIFACTINFO
 _ARTIFACTSBYSERVICE_SYSROOT.containing_type = _ARTIFACTSBYSERVICE
 _ARTIFACTSBYSERVICE_SYSROOT_ARTIFACTTYPE.containing_type = _ARTIFACTSBYSERVICE_SYSROOT
 _ARTIFACTSBYSERVICE_TEST_ARTIFACTINFO.fields_by_name['artifact_types'].enum_type = _ARTIFACTSBYSERVICE_TEST_ARTIFACTTYPE
-_ARTIFACTSBYSERVICE_TEST_ARTIFACTINFO.fields_by_name['publish_condition'].enum_type = _ARTIFACTSBYSERVICE_PUBLISHCONDITION
 _ARTIFACTSBYSERVICE_TEST_ARTIFACTINFO.fields_by_name['code_coverage_upload_info'].message_type = _ARTIFACTSBYSERVICE_CODECOVERAGEUPLOADINFO
 _ARTIFACTSBYSERVICE_TEST_ARTIFACTINFO.containing_type = _ARTIFACTSBYSERVICE_TEST
 _ARTIFACTSBYSERVICE_TEST.fields_by_name['input_artifacts'].message_type = _ARTIFACTSBYSERVICE_TEST_ARTIFACTINFO
@@ -3570,7 +3482,6 @@
 _ARTIFACTSBYSERVICE_TEST.containing_type = _ARTIFACTSBYSERVICE
 _ARTIFACTSBYSERVICE_TEST_ARTIFACTTYPE.containing_type = _ARTIFACTSBYSERVICE_TEST
 _ARTIFACTSBYSERVICE_FIRMWARE_ARTIFACTINFO.fields_by_name['artifact_types'].enum_type = _ARTIFACTSBYSERVICE_FIRMWARE_ARTIFACTTYPE
-_ARTIFACTSBYSERVICE_FIRMWARE_ARTIFACTINFO.fields_by_name['publish_condition'].enum_type = _ARTIFACTSBYSERVICE_PUBLISHCONDITION
 _ARTIFACTSBYSERVICE_FIRMWARE_ARTIFACTINFO.fields_by_name['location'].enum_type = _FWLOCATION
 _ARTIFACTSBYSERVICE_FIRMWARE_ARTIFACTINFO.fields_by_name['code_coverage_upload_info'].message_type = _ARTIFACTSBYSERVICE_CODECOVERAGEUPLOADINFO
 _ARTIFACTSBYSERVICE_FIRMWARE_ARTIFACTINFO.containing_type = _ARTIFACTSBYSERVICE_FIRMWARE
@@ -3579,7 +3490,6 @@
 _ARTIFACTSBYSERVICE_FIRMWARE.containing_type = _ARTIFACTSBYSERVICE
 _ARTIFACTSBYSERVICE_FIRMWARE_ARTIFACTTYPE.containing_type = _ARTIFACTSBYSERVICE_FIRMWARE
 _ARTIFACTSBYSERVICE_INFRA_ARTIFACTINFO.fields_by_name['artifact_types'].enum_type = _ARTIFACTSBYSERVICE_INFRA_ARTIFACTTYPE
-_ARTIFACTSBYSERVICE_INFRA_ARTIFACTINFO.fields_by_name['publish_condition'].enum_type = _ARTIFACTSBYSERVICE_PUBLISHCONDITION
 _ARTIFACTSBYSERVICE_INFRA_ARTIFACTINFO.containing_type = _ARTIFACTSBYSERVICE_INFRA
 _ARTIFACTSBYSERVICE_INFRA.fields_by_name['input_artifacts'].message_type = _ARTIFACTSBYSERVICE_INFRA_ARTIFACTINFO
 _ARTIFACTSBYSERVICE_INFRA.fields_by_name['output_artifacts'].message_type = _ARTIFACTSBYSERVICE_INFRA_ARTIFACTINFO
@@ -3594,7 +3504,6 @@
 _ARTIFACTSBYSERVICE.fields_by_name['profile_info'].message_type = _ARTIFACTPROFILEINFO
 _ARTIFACTSBYSERVICE.fields_by_name['firmware'].message_type = _ARTIFACTSBYSERVICE_FIRMWARE
 _ARTIFACTSBYSERVICE.fields_by_name['infra'].message_type = _ARTIFACTSBYSERVICE_INFRA
-_ARTIFACTSBYSERVICE_PUBLISHCONDITION.containing_type = _ARTIFACTSBYSERVICE
 _UPLOADEDARTIFACTSBYSERVICE_LEGACY_ARTIFACTPATHS.fields_by_name['artifact_type'].enum_type = _ARTIFACTSBYSERVICE_LEGACY_ARTIFACTTYPE
 _UPLOADEDARTIFACTSBYSERVICE_LEGACY_ARTIFACTPATHS.fields_by_name['paths'].message_type = _PATH
 _UPLOADEDARTIFACTSBYSERVICE_LEGACY_ARTIFACTPATHS.containing_type = _UPLOADEDARTIFACTSBYSERVICE_LEGACY
@@ -3648,6 +3557,7 @@
 DESCRIPTOR.message_types_by_name['GcsPath'] = _GCSPATH
 DESCRIPTOR.message_types_by_name['Chroot'] = _CHROOT
 DESCRIPTOR.message_types_by_name['Feature'] = _FEATURE
+DESCRIPTOR.message_types_by_name['RemoteexecConfig'] = _REMOTEEXECCONFIG
 DESCRIPTOR.message_types_by_name['GomaConfig'] = _GOMACONFIG
 DESCRIPTOR.message_types_by_name['GomaArtifacts'] = _GOMAARTIFACTS
 DESCRIPTOR.message_types_by_name['PackageInfo'] = _PACKAGEINFO
@@ -3672,7 +3582,6 @@
 DESCRIPTOR.enum_types_by_name['Channel'] = _CHANNEL
 DESCRIPTOR.enum_types_by_name['DeltaType'] = _DELTATYPE
 DESCRIPTOR.enum_types_by_name['FwLocation'] = _FWLOCATION
-DESCRIPTOR.enum_types_by_name['AFDOArtifactType'] = _AFDOARTIFACTTYPE
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
 BuildTarget = _reflection.GeneratedProtocolMessageType('BuildTarget', (_message.Message,), {
@@ -3711,6 +3620,13 @@
   })
 _sym_db.RegisterMessage(Feature)
 
+RemoteexecConfig = _reflection.GeneratedProtocolMessageType('RemoteexecConfig', (_message.Message,), {
+  'DESCRIPTOR' : _REMOTEEXECCONFIG,
+  '__module__' : 'chromiumos.common_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.RemoteexecConfig)
+  })
+_sym_db.RegisterMessage(RemoteexecConfig)
+
 GomaConfig = _reflection.GeneratedProtocolMessageType('GomaConfig', (_message.Message,), {
   'DESCRIPTOR' : _GOMACONFIG,
   '__module__' : 'chromiumos.common_pb2'
diff --git a/api/gen/chromiumos/config/api/component_pb2.py b/api/gen/chromiumos/config/api/component_pb2.py
index da229a9..3f4f137 100644
--- a/api/gen/chromiumos/config/api/component_pb2.py
+++ b/api/gen/chromiumos/config/api/component_pb2.py
@@ -13,6 +13,7 @@
 
 from chromite.api.gen.chromiumos.config.api import component_id_pb2 as chromiumos_dot_config_dot_api_dot_component__id__pb2
 from chromite.api.gen.chromiumos.config.api import partner_id_pb2 as chromiumos_dot_config_dot_api_dot_partner__id__pb2
+from chromite.third_party.google.protobuf import wrappers_pb2 as google_dot_protobuf_dot_wrappers__pb2
 
 
 DESCRIPTOR = _descriptor.FileDescriptor(
@@ -21,9 +22,9 @@
   syntax='proto3',
   serialized_options=b'Z(go.chromium.org/chromiumos/config/go/api',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n%chromiumos/config/api/component.proto\x12\x15\x63hromiumos.config.api\x1a(chromiumos/config/api/component_id.proto\x1a&chromiumos/config/api/partner_id.proto\"\x8d(\n\tComponent\x12.\n\x02id\x18\x01 \x01(\x0b\x32\".chromiumos.config.api.ComponentId\x12\x39\n\x0fmanufacturer_id\x18\x08 \x01(\x0b\x32 .chromiumos.config.api.PartnerId\x12\x0c\n\x04name\x18\t \x01(\t\x12\x11\n\thwid_type\x18\x19 \x01(\t\x12\x12\n\nhwid_label\x18\x14 \x01(\t\x12\x36\n\x06\x61vl_id\x18\x15 \x01(\x0b\x32&.chromiumos.config.api.Component.AVLId\x12\x13\n\x0bpart_number\x18\x16 \x01(\t\x12\x33\n\x03soc\x18\x02 \x01(\x0b\x32$.chromiumos.config.api.Component.SocH\x00\x12\x39\n\x06memory\x18\x03 \x01(\x0b\x32\'.chromiumos.config.api.Component.MemoryH\x00\x12?\n\tbluetooth\x18\x04 \x01(\x0b\x32*.chromiumos.config.api.Component.BluetoothH\x00\x12\x39\n\x06\x63\x61mera\x18\x05 \x01(\x0b\x32\'.chromiumos.config.api.Component.CameraH\x00\x12=\n\x0btouchscreen\x18\x06 \x01(\x0b\x32&.chromiumos.config.api.Component.TouchH\x00\x12\x35\n\x04wifi\x18\x07 \x01(\x0b\x32%.chromiumos.config.api.Component.WifiH\x00\x12:\n\x08touchpad\x18\n \x01(\x0b\x32&.chromiumos.config.api.Component.TouchH\x00\x12\x46\n\rdisplay_panel\x18\x0b \x01(\x0b\x32-.chromiumos.config.api.Component.DisplayPanelH\x00\x12\x42\n\x0b\x61udio_codec\x18\x0c \x01(\x0b\x32+.chromiumos.config.api.Component.AudioCodecH\x00\x12;\n\x07\x62\x61ttery\x18\r \x01(\x0b\x32(.chromiumos.config.api.Component.BatteryH\x00\x12\x43\n\rec_flash_chip\x18\x0e \x01(\x0b\x32*.chromiumos.config.api.Component.FlashChipH\x00\x12G\n\x11system_flash_chip\x18\x0f \x01(\x0b\x32*.chromiumos.config.api.Component.FlashChipH\x00\x12\x41\n\x02\x65\x63\x18\x10 \x01(\x0b\x32\x33.chromiumos.config.api.Component.EmbeddedControllerH\x00\x12;\n\x07storage\x18\x11 \x01(\x0b\x32(.chromiumos.config.api.Component.StorageH\x00\x12\x33\n\x03tpm\x18\x12 \x01(\x0b\x32$.chromiumos.config.api.Component.TpmH\x00\x12\x42\n\x08usb_host\x18\x13 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.UsbH\x00\x12\x39\n\x06stylus\x18\x17 \x01(\x0b\x32\'.chromiumos.config.api.Component.StylusH\x00\x12?\n\tamplifier\x18\x18 \x01(\x0b\x32*.chromiumos.config.api.Component.AmplifierH\x00\x12M\n\x0c\x64p_converter\x18\x1a \x01(\x0b\x32\x35.chromiumos.config.api.Component.DisplayPortConverterH\x00\x12=\n\x08\x63\x65llular\x18\x1b \x01(\x0b\x32).chromiumos.config.api.Component.CellularH\x00\x1a!\n\x05\x41VLId\x12\x0b\n\x03\x63id\x18\x01 \x01(\x05\x12\x0b\n\x03qid\x18\x02 \x01(\x05\x1a\xb7\x01\n\tInterface\x1a&\n\x03I2C\x12\x0f\n\x07product\x18\x01 \x01(\t\x12\x0e\n\x06vendor\x18\x02 \x01(\t\x1a@\n\x03Usb\x12\x11\n\tvendor_id\x18\x01 \x01(\t\x12\x12\n\nproduct_id\x18\x02 \x01(\t\x12\x12\n\nbcd_device\x18\x03 \x01(\t\x1a@\n\x03Pci\x12\x11\n\tvendor_id\x18\x01 \x01(\t\x12\x11\n\tdevice_id\x18\x02 \x01(\t\x12\x13\n\x0brevision_id\x18\x03 \x01(\t\x1a\xf7\x02\n\x03Soc\x12;\n\x06\x66\x61mily\x18\x01 \x01(\x0b\x32+.chromiumos.config.api.Component.Soc.Family\x12\r\n\x05model\x18\x02 \x01(\t\x12\r\n\x05\x63ores\x18\x03 \x01(\x05\x12>\n\x08\x66\x65\x61tures\x18\x04 \x03(\x0e\x32,.chromiumos.config.api.Component.Soc.Feature\x1aW\n\x06\x46\x61mily\x12?\n\x04\x61rch\x18\x01 \x01(\x0e\x32\x31.chromiumos.config.api.Component.Soc.Architecture\x12\x0c\n\x04name\x18\x02 \x01(\t\"S\n\x0c\x41rchitecture\x12\x1a\n\x16\x41RCHITECTURE_UNDEFINED\x10\x00\x12\x07\n\x03X86\x10\x01\x12\n\n\x06X86_64\x10\x02\x12\x07\n\x03\x41RM\x10\x03\x12\t\n\x05\x41RM64\x10\x04\"\'\n\x07\x46\x65\x61ture\x12\x13\n\x0f\x46\x45\x41TURE_UNKNOWN\x10\x00\x12\x07\n\x03SMT\x10\x01\x1a\xb4\x02\n\x06Memory\x12@\n\x07profile\x18\x01 \x01(\x0b\x32/.chromiumos.config.api.Component.Memory.Profile\x12\x13\n\x0bpart_number\x18\x02 \x01(\t\x1ap\n\x07Profile\x12:\n\x04type\x18\x01 \x01(\x0e\x32,.chromiumos.config.api.Component.Memory.Type\x12\x11\n\tspeed_mhz\x18\x02 \x01(\x05\x12\x16\n\x0esize_megabytes\x18\x03 \x01(\x05\"[\n\x04Type\x12\x12\n\x0eTYPE_UNDEFINED\x10\x00\x12\x07\n\x03\x44\x44R\x10\x01\x12\x08\n\x04\x44\x44R2\x10\x02\x12\x08\n\x04\x44\x44R3\x10\x03\x12\x08\n\x04\x44\x44R4\x10\x04\x12\x0b\n\x07LP_DDR3\x10\x05\x12\x0b\n\x07LP_DDR4\x10\x06J\x04\x08\x03\x10\x04\x1aZ\n\tBluetooth\x12;\n\x03usb\x18\x04 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.UsbJ\x04\x08\x01\x10\x02J\x04\x08\x02\x10\x03J\x04\x08\x03\x10\x04\x1a\x93\x03\n\x06\x43\x61mera\x12\x41\n\x08\x66\x65\x61tures\x18\x01 \x03(\x0e\x32/.chromiumos.config.api.Component.Camera.Feature\x12\x45\n\nclock_type\x18\x02 \x01(\x0e\x32\x31.chromiumos.config.api.Component.Camera.ClockType\x12=\n\x03usb\x18\x03 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.UsbH\x00\x12=\n\x03pci\x18\x04 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.PciH\x00\"0\n\x07\x46\x65\x61ture\x12\x13\n\x0f\x46\x45\x41TURE_UNKNOWN\x10\x00\x12\x10\n\x0c\x41\x43TIVITY_LED\x10\x01\"B\n\tClockType\x12\x18\n\x14\x43LOCK_TYPE_UNDEFINED\x10\x00\x12\r\n\tMONOTONIC\x10\x01\x12\x0c\n\x08\x42OOTTIME\x10\x02\x42\x0b\n\tinterface\x1a\xc9\x02\n\x0c\x44isplayPanel\x12\x12\n\nproduct_id\x18\x01 \x01(\t\x12L\n\nproperties\x18\x02 \x01(\x0b\x32\x38.chromiumos.config.api.Component.DisplayPanel.Properties\x1a\xad\x01\n\nProperties\x12\x10\n\x08width_px\x18\x01 \x01(\x05\x12\x11\n\theight_px\x18\x02 \x01(\x05\x12\x1a\n\x12\x64iagonal_milliinch\x18\x03 \x01(\x05\x12\x15\n\rpixels_per_in\x18\x04 \x01(\x05\x12G\n\x08\x66\x65\x61tures\x18\x05 \x03(\x0e\x32\x35.chromiumos.config.api.Component.DisplayPanel.Feature\"\'\n\x07\x46\x65\x61ture\x12\x13\n\x0f\x46\x45\x41TURE_UNKNOWN\x10\x00\x12\x07\n\x03HDR\x10\x01\x1a\x9e\x02\n\x05Touch\x12\x12\n\nproduct_id\x18\x02 \x01(\t\x12\x12\n\nfw_version\x18\x03 \x01(\t\x12\x16\n\x0eproduct_series\x18\x05 \x01(\t\x12\x13\n\x0b\x66w_checksum\x18\x06 \x01(\t\x12>\n\x04type\x18\x07 \x01(\x0e\x32\x30.chromiumos.config.api.Component.Touch.TouchType\x12;\n\x03usb\x18\x08 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.Usb\"7\n\tTouchType\x12\x18\n\x14TOUCH_TYPE_UNDEFINED\x10\x00\x12\x07\n\x03USB\x10\x01\x12\x07\n\x03I2C\x10\x02J\x04\x08\x01\x10\x02J\x04\x08\x04\x10\x05\x1a\xc8\x02\n\x04Wifi\x12=\n\x03pci\x18\x01 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.PciH\x00\x12T\n\x18supported_wlan_protocols\x18\x02 \x03(\x0e\x32\x32.chromiumos.config.api.Component.Wifi.WLANProtocol\"\x9d\x01\n\x0cWLANProtocol\x12\x19\n\x15WLAN_PROTOCOL_UNKNOWN\x10\x00\x12\x11\n\rIEEE_802_11_A\x10\x01\x12\x11\n\rIEEE_802_11_B\x10\x02\x12\x11\n\rIEEE_802_11_G\x10\x03\x12\x11\n\rIEEE_802_11_N\x10\x04\x12\x12\n\x0eIEEE_802_11_AC\x10\x05\x12\x12\n\x0eIEEE_802_11_AX\x10\x06\x42\x0b\n\tinterface\x1a\xe7\x01\n\rQualification\x12\x38\n\x0c\x63omponent_id\x18\x01 \x01(\x0b\x32\".chromiumos.config.api.ComponentId\x12\x45\n\x06status\x18\x02 \x01(\x0e\x32\x35.chromiumos.config.api.Component.Qualification.Status\"U\n\x06Status\x12\x12\n\x0eSTATUS_UNKNOWN\x10\x00\x12\r\n\tREQUESTED\x10\x01\x12\x19\n\x15TECHNICALLY_QUALIFIED\x10\x02\x12\r\n\tQUALIFIED\x10\x03\x1a\x9a\x01\n\tAmplifier\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x44\n\x08\x66\x65\x61tures\x18\x02 \x03(\x0e\x32\x32.chromiumos.config.api.Component.Amplifier.Feature\"9\n\x07\x46\x65\x61ture\x12\x13\n\x0f\x46\x45\x41TURE_UNKNOWN\x10\x00\x12\x19\n\x15\x42OOT_TIME_CALIBRATION\x10\x01\x1a\x1a\n\nAudioCodec\x12\x0c\n\x04name\x18\x01 \x01(\t\x1a\x9a\x01\n\x07\x42\x61ttery\x12\r\n\x05model\x18\x01 \x01(\t\x12G\n\ntechnology\x18\x02 \x01(\x0e\x32\x33.chromiumos.config.api.Component.Battery.Technology\"7\n\nTechnology\x12\x10\n\x0cTECH_UNKNOWN\x10\x00\x12\n\n\x06LI_ION\x10\x01\x12\x0b\n\x07LI_POLY\x10\x02\x1a \n\tFlashChip\x12\x13\n\x0bpart_number\x18\x01 \x01(\t\x1a)\n\x12\x45mbeddedController\x12\x13\n\x0bpart_number\x18\x01 \x01(\t\x1a\x86\x02\n\x07Storage\x12\x14\n\x0c\x65mmc5_fw_ver\x18\x01 \x01(\t\x12\x0e\n\x06manfid\x18\x02 \x01(\t\x12\x0c\n\x04name\x18\x03 \x01(\t\x12\r\n\x05oemid\x18\x04 \x01(\t\x12\x0b\n\x03prv\x18\x05 \x01(\t\x12\x0f\n\x07sectors\x18\x06 \x01(\t\x12\x42\n\x04type\x18\x07 \x01(\x0e\x32\x34.chromiumos.config.api.Component.Storage.StorageType\x12\x0f\n\x07size_gb\x18\x08 \x01(\r\"E\n\x0bStorageType\x12\x18\n\x14STORAGE_TYPE_UNKNOWN\x10\x00\x12\x08\n\x04\x45MMC\x10\x01\x12\x08\n\x04NVME\x10\x02\x12\x08\n\x04SATA\x10\x03\x1a\x31\n\x03Tpm\x12\x19\n\x11manufacturer_info\x18\x01 \x01(\t\x12\x0f\n\x07version\x18\x02 \x01(\t\x1a\x93\x01\n\x06Stylus\x12=\n\x03usb\x18\x01 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.UsbH\x00\x12=\n\x03i2c\x18\x02 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.I2CH\x00\x42\x0b\n\tinterface\x1a$\n\x14\x44isplayPortConverter\x12\x0c\n\x04name\x18\x01 \x01(\t\x1aV\n\x08\x43\x65llular\x12=\n\x03usb\x18\x01 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.UsbH\x00\x42\x0b\n\tinterfaceB\x06\n\x04typeB*Z(go.chromium.org/chromiumos/config/go/apib\x06proto3'
+  serialized_pb=b'\n%chromiumos/config/api/component.proto\x12\x15\x63hromiumos.config.api\x1a(chromiumos/config/api/component_id.proto\x1a&chromiumos/config/api/partner_id.proto\x1a\x1egoogle/protobuf/wrappers.proto\"\xb4-\n\tComponent\x12.\n\x02id\x18\x01 \x01(\x0b\x32\".chromiumos.config.api.ComponentId\x12\x39\n\x0fmanufacturer_id\x18\x08 \x01(\x0b\x32 .chromiumos.config.api.PartnerId\x12\x0c\n\x04name\x18\t \x01(\t\x12\x11\n\thwid_type\x18\x19 \x01(\t\x12\x12\n\nhwid_label\x18\x14 \x01(\t\x12\x36\n\x06\x61vl_id\x18\x15 \x01(\x0b\x32&.chromiumos.config.api.Component.AVLId\x12\x13\n\x0bpart_number\x18\x16 \x01(\t\x12\x46\n\x0esupport_status\x18\x1c \x01(\x0e\x32..chromiumos.config.api.Component.SupportStatus\x12\x33\n\x03soc\x18\x02 \x01(\x0b\x32$.chromiumos.config.api.Component.SocH\x00\x12\x39\n\x06memory\x18\x03 \x01(\x0b\x32\'.chromiumos.config.api.Component.MemoryH\x00\x12?\n\tbluetooth\x18\x04 \x01(\x0b\x32*.chromiumos.config.api.Component.BluetoothH\x00\x12\x39\n\x06\x63\x61mera\x18\x05 \x01(\x0b\x32\'.chromiumos.config.api.Component.CameraH\x00\x12=\n\x0btouchscreen\x18\x06 \x01(\x0b\x32&.chromiumos.config.api.Component.TouchH\x00\x12\x35\n\x04wifi\x18\x07 \x01(\x0b\x32%.chromiumos.config.api.Component.WifiH\x00\x12:\n\x08touchpad\x18\n \x01(\x0b\x32&.chromiumos.config.api.Component.TouchH\x00\x12\x46\n\rdisplay_panel\x18\x0b \x01(\x0b\x32-.chromiumos.config.api.Component.DisplayPanelH\x00\x12\x42\n\x0b\x61udio_codec\x18\x0c \x01(\x0b\x32+.chromiumos.config.api.Component.AudioCodecH\x00\x12;\n\x07\x62\x61ttery\x18\r \x01(\x0b\x32(.chromiumos.config.api.Component.BatteryH\x00\x12\x43\n\rec_flash_chip\x18\x0e \x01(\x0b\x32*.chromiumos.config.api.Component.FlashChipH\x00\x12G\n\x11system_flash_chip\x18\x0f \x01(\x0b\x32*.chromiumos.config.api.Component.FlashChipH\x00\x12\x41\n\x02\x65\x63\x18\x10 \x01(\x0b\x32\x33.chromiumos.config.api.Component.EmbeddedControllerH\x00\x12;\n\x07storage\x18\x11 \x01(\x0b\x32(.chromiumos.config.api.Component.StorageH\x00\x12\x33\n\x03tpm\x18\x12 \x01(\x0b\x32$.chromiumos.config.api.Component.TpmH\x00\x12\x42\n\x08usb_host\x18\x13 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.UsbH\x00\x12\x39\n\x06stylus\x18\x17 \x01(\x0b\x32\'.chromiumos.config.api.Component.StylusH\x00\x12?\n\tamplifier\x18\x18 \x01(\x0b\x32*.chromiumos.config.api.Component.AmplifierH\x00\x12M\n\x0c\x64p_converter\x18\x1a \x01(\x0b\x32\x35.chromiumos.config.api.Component.DisplayPortConverterH\x00\x12=\n\x08\x63\x65llular\x18\x1b \x01(\x0b\x32).chromiumos.config.api.Component.CellularH\x00\x1a!\n\x05\x41VLId\x12\x0b\n\x03\x63id\x18\x01 \x01(\x05\x12\x0b\n\x03qid\x18\x02 \x01(\x05\x1a\xc9\x01\n\tInterface\x1a&\n\x03I2C\x12\x0f\n\x07product\x18\x01 \x01(\t\x12\x0e\n\x06vendor\x18\x02 \x01(\t\x1a@\n\x03Usb\x12\x11\n\tvendor_id\x18\x01 \x01(\t\x12\x12\n\nproduct_id\x18\x02 \x01(\t\x12\x12\n\nbcd_device\x18\x03 \x01(\t\x1aR\n\x03Pci\x12\x11\n\tvendor_id\x18\x01 \x01(\t\x12\x11\n\tdevice_id\x18\x02 \x01(\t\x12\x13\n\x0brevision_id\x18\x03 \x01(\t\x12\x10\n\x08\x63lass_id\x18\x04 \x01(\t\x1a\x83\x03\n\x03Soc\x12;\n\x06\x66\x61mily\x18\x01 \x01(\x0b\x32+.chromiumos.config.api.Component.Soc.Family\x12\r\n\x05model\x18\x02 \x01(\t\x12\r\n\x05\x63ores\x18\x03 \x01(\x05\x12>\n\x08\x66\x65\x61tures\x18\x04 \x03(\x0e\x32,.chromiumos.config.api.Component.Soc.Feature\x1aW\n\x06\x46\x61mily\x12?\n\x04\x61rch\x18\x01 \x01(\x0e\x32\x31.chromiumos.config.api.Component.Soc.Architecture\x12\x0c\n\x04name\x18\x02 \x01(\t\"S\n\x0c\x41rchitecture\x12\x1a\n\x16\x41RCHITECTURE_UNDEFINED\x10\x00\x12\x07\n\x03X86\x10\x01\x12\n\n\x06X86_64\x10\x02\x12\x07\n\x03\x41RM\x10\x03\x12\t\n\x05\x41RM64\x10\x04\"3\n\x07\x46\x65\x61ture\x12\x13\n\x0f\x46\x45\x41TURE_UNKNOWN\x10\x00\x12\x07\n\x03SMT\x10\x01\x12\n\n\x06SHA_NI\x10\x02\x1a\xb4\x02\n\x06Memory\x12@\n\x07profile\x18\x01 \x01(\x0b\x32/.chromiumos.config.api.Component.Memory.Profile\x12\x13\n\x0bpart_number\x18\x02 \x01(\t\x1ap\n\x07Profile\x12:\n\x04type\x18\x01 \x01(\x0e\x32,.chromiumos.config.api.Component.Memory.Type\x12\x11\n\tspeed_mhz\x18\x02 \x01(\x05\x12\x16\n\x0esize_megabytes\x18\x03 \x01(\x05\"[\n\x04Type\x12\x12\n\x0eTYPE_UNDEFINED\x10\x00\x12\x07\n\x03\x44\x44R\x10\x01\x12\x08\n\x04\x44\x44R2\x10\x02\x12\x08\n\x04\x44\x44R3\x10\x03\x12\x08\n\x04\x44\x44R4\x10\x04\x12\x0b\n\x07LP_DDR3\x10\x05\x12\x0b\n\x07LP_DDR4\x10\x06J\x04\x08\x03\x10\x04\x1aZ\n\tBluetooth\x12;\n\x03usb\x18\x04 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.UsbJ\x04\x08\x01\x10\x02J\x04\x08\x02\x10\x03J\x04\x08\x03\x10\x04\x1a\x93\x03\n\x06\x43\x61mera\x12\x41\n\x08\x66\x65\x61tures\x18\x01 \x03(\x0e\x32/.chromiumos.config.api.Component.Camera.Feature\x12\x45\n\nclock_type\x18\x02 \x01(\x0e\x32\x31.chromiumos.config.api.Component.Camera.ClockType\x12=\n\x03usb\x18\x03 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.UsbH\x00\x12=\n\x03pci\x18\x04 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.PciH\x00\"0\n\x07\x46\x65\x61ture\x12\x13\n\x0f\x46\x45\x41TURE_UNKNOWN\x10\x00\x12\x10\n\x0c\x41\x43TIVITY_LED\x10\x01\"B\n\tClockType\x12\x18\n\x14\x43LOCK_TYPE_UNDEFINED\x10\x00\x12\r\n\tMONOTONIC\x10\x01\x12\x0c\n\x08\x42OOTTIME\x10\x02\x42\x0b\n\tinterface\x1a\xae\x04\n\x0c\x44isplayPanel\x12\x12\n\nproduct_id\x18\x01 \x01(\t\x12L\n\nproperties\x18\x02 \x01(\x0b\x32\x38.chromiumos.config.api.Component.DisplayPanel.Properties\x1a\x92\x03\n\nProperties\x12\x10\n\x08width_px\x18\x01 \x01(\x05\x12\x11\n\theight_px\x18\x02 \x01(\x05\x12\x1a\n\x12\x64iagonal_milliinch\x18\x03 \x01(\x05\x12\x15\n\rpixels_per_in\x18\x04 \x01(\x05\x12G\n\x08\x66\x65\x61tures\x18\x05 \x03(\x0e\x32\x35.chromiumos.config.api.Component.DisplayPanel.Feature\x12#\n\x1bmin_visible_backlight_level\x18\x06 \x01(\r\x12@\n\x1aturn_off_screen_timeout_ms\x18\x07 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12!\n\x19no_als_battery_brightness\x18\x08 \x01(\x01\x12\x1c\n\x14no_als_ac_brightness\x18\t \x01(\x01\x12;\n\tals_steps\x18\n \x03(\x0b\x32(.chromiumos.config.api.Component.AlsStep\"\'\n\x07\x46\x65\x61ture\x12\x13\n\x0f\x46\x45\x41TURE_UNKNOWN\x10\x00\x12\x07\n\x03HDR\x10\x01\x1a\x9e\x02\n\x05Touch\x12\x12\n\nproduct_id\x18\x02 \x01(\t\x12\x12\n\nfw_version\x18\x03 \x01(\t\x12\x16\n\x0eproduct_series\x18\x05 \x01(\t\x12\x13\n\x0b\x66w_checksum\x18\x06 \x01(\t\x12>\n\x04type\x18\x07 \x01(\x0e\x32\x30.chromiumos.config.api.Component.Touch.TouchType\x12;\n\x03usb\x18\x08 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.Usb\"7\n\tTouchType\x12\x18\n\x14TOUCH_TYPE_UNDEFINED\x10\x00\x12\x07\n\x03USB\x10\x01\x12\x07\n\x03I2C\x10\x02J\x04\x08\x01\x10\x02J\x04\x08\x04\x10\x05\x1a\xc8\x02\n\x04Wifi\x12=\n\x03pci\x18\x01 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.PciH\x00\x12T\n\x18supported_wlan_protocols\x18\x02 \x03(\x0e\x32\x32.chromiumos.config.api.Component.Wifi.WLANProtocol\"\x9d\x01\n\x0cWLANProtocol\x12\x19\n\x15WLAN_PROTOCOL_UNKNOWN\x10\x00\x12\x11\n\rIEEE_802_11_A\x10\x01\x12\x11\n\rIEEE_802_11_B\x10\x02\x12\x11\n\rIEEE_802_11_G\x10\x03\x12\x11\n\rIEEE_802_11_N\x10\x04\x12\x12\n\x0eIEEE_802_11_AC\x10\x05\x12\x12\n\x0eIEEE_802_11_AX\x10\x06\x42\x0b\n\tinterface\x1a\xe7\x01\n\rQualification\x12\x38\n\x0c\x63omponent_id\x18\x01 \x01(\x0b\x32\".chromiumos.config.api.ComponentId\x12\x45\n\x06status\x18\x02 \x01(\x0e\x32\x35.chromiumos.config.api.Component.Qualification.Status\"U\n\x06Status\x12\x12\n\x0eSTATUS_UNKNOWN\x10\x00\x12\r\n\tREQUESTED\x10\x01\x12\x19\n\x15TECHNICALLY_QUALIFIED\x10\x02\x12\r\n\tQUALIFIED\x10\x03\x1a\x9a\x01\n\tAmplifier\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x44\n\x08\x66\x65\x61tures\x18\x02 \x03(\x0e\x32\x32.chromiumos.config.api.Component.Amplifier.Feature\"9\n\x07\x46\x65\x61ture\x12\x13\n\x0f\x46\x45\x41TURE_UNKNOWN\x10\x00\x12\x19\n\x15\x42OOT_TIME_CALIBRATION\x10\x01\x1a\x1a\n\nAudioCodec\x12\x0c\n\x04name\x18\x01 \x01(\t\x1a\x9a\x01\n\x07\x42\x61ttery\x12\r\n\x05model\x18\x01 \x01(\t\x12G\n\ntechnology\x18\x02 \x01(\x0e\x32\x33.chromiumos.config.api.Component.Battery.Technology\"7\n\nTechnology\x12\x10\n\x0cTECH_UNKNOWN\x10\x00\x12\n\n\x06LI_ION\x10\x01\x12\x0b\n\x07LI_POLY\x10\x02\x1a \n\tFlashChip\x12\x13\n\x0bpart_number\x18\x01 \x01(\t\x1a)\n\x12\x45mbeddedController\x12\x13\n\x0bpart_number\x18\x01 \x01(\t\x1a\xd2\x02\n\x07Storage\x12\x14\n\x0c\x65mmc5_fw_ver\x18\x01 \x01(\t\x12\x0e\n\x06manfid\x18\x02 \x01(\t\x12\x0c\n\x04name\x18\x03 \x01(\t\x12\r\n\x05oemid\x18\x04 \x01(\t\x12\x0b\n\x03prv\x18\x05 \x01(\t\x12\x0f\n\x07sectors\x18\x06 \x01(\t\x12\x42\n\x04type\x18\x07 \x01(\x0e\x32\x34.chromiumos.config.api.Component.Storage.StorageType\x12\x0f\n\x07size_gb\x18\x08 \x01(\r\x12=\n\x03pci\x18\t \x01(\x0b\x32..chromiumos.config.api.Component.Interface.PciH\x00\"E\n\x0bStorageType\x12\x18\n\x14STORAGE_TYPE_UNKNOWN\x10\x00\x12\x08\n\x04\x45MMC\x10\x01\x12\x08\n\x04NVME\x10\x02\x12\x08\n\x04SATA\x10\x03\x42\x0b\n\tinterface\x1a\x31\n\x03Tpm\x12\x19\n\x11manufacturer_info\x18\x01 \x01(\t\x12\x0f\n\x07version\x18\x02 \x01(\t\x1a\x93\x01\n\x06Stylus\x12=\n\x03usb\x18\x01 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.UsbH\x00\x12=\n\x03i2c\x18\x02 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.I2CH\x00\x42\x0b\n\tinterface\x1a$\n\x14\x44isplayPortConverter\x12\x0c\n\x04name\x18\x01 \x01(\t\x1aV\n\x08\x43\x65llular\x12=\n\x03usb\x18\x01 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.UsbH\x00\x42\x0b\n\tinterface\x1a\x8a\x01\n\x07\x41lsStep\x12\x1c\n\x14\x61\x63_backlight_percent\x18\x01 \x01(\x01\x12!\n\x19\x62\x61ttery_backlight_percent\x18\x02 \x01(\x01\x12\x1e\n\x16lux_decrease_threshold\x18\x03 \x01(\x05\x12\x1e\n\x16lux_increase_threshold\x18\x04 \x01(\x05\"\x80\x01\n\rSupportStatus\x12\x12\n\x0eSTATUS_UNKNOWN\x10\x00\x12\x14\n\x10STATUS_SUPPORTED\x10\x01\x12\x15\n\x11STATUS_DEPRECATED\x10\x02\x12\x16\n\x12STATUS_UNQUALIFIED\x10\x03\x12\x16\n\x12STATUS_UNSUPPORTED\x10\x04\x42\x06\n\x04typeB*Z(go.chromium.org/chromiumos/config/go/apib\x06proto3'
   ,
-  dependencies=[chromiumos_dot_config_dot_api_dot_component__id__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_partner__id__pb2.DESCRIPTOR,])
+  dependencies=[chromiumos_dot_config_dot_api_dot_component__id__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_partner__id__pb2.DESCRIPTOR,google_dot_protobuf_dot_wrappers__pb2.DESCRIPTOR,])
 
 
 
@@ -62,8 +63,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2142,
-  serialized_end=2225,
+  serialized_start=2264,
+  serialized_end=2347,
 )
 _sym_db.RegisterEnumDescriptor(_COMPONENT_SOC_ARCHITECTURE)
 
@@ -84,11 +85,16 @@
       serialized_options=None,
       type=None,
       create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='SHA_NI', index=2, number=2,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2227,
-  serialized_end=2266,
+  serialized_start=2349,
+  serialized_end=2400,
 )
 _sym_db.RegisterEnumDescriptor(_COMPONENT_SOC_FEATURE)
 
@@ -137,8 +143,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2480,
-  serialized_end=2571,
+  serialized_start=2614,
+  serialized_end=2705,
 )
 _sym_db.RegisterEnumDescriptor(_COMPONENT_MEMORY_TYPE)
 
@@ -162,8 +168,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2946,
-  serialized_end=2994,
+  serialized_start=3080,
+  serialized_end=3128,
 )
 _sym_db.RegisterEnumDescriptor(_COMPONENT_CAMERA_FEATURE)
 
@@ -192,8 +198,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2996,
-  serialized_end=3062,
+  serialized_start=3130,
+  serialized_end=3196,
 )
 _sym_db.RegisterEnumDescriptor(_COMPONENT_CAMERA_CLOCKTYPE)
 
@@ -217,8 +223,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=3368,
-  serialized_end=3407,
+  serialized_start=3731,
+  serialized_end=3770,
 )
 _sym_db.RegisterEnumDescriptor(_COMPONENT_DISPLAYPANEL_FEATURE)
 
@@ -247,8 +253,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=3629,
-  serialized_end=3684,
+  serialized_start=3992,
+  serialized_end=4047,
 )
 _sym_db.RegisterEnumDescriptor(_COMPONENT_TOUCH_TOUCHTYPE)
 
@@ -297,8 +303,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=3857,
-  serialized_end=4014,
+  serialized_start=4220,
+  serialized_end=4377,
 )
 _sym_db.RegisterEnumDescriptor(_COMPONENT_WIFI_WLANPROTOCOL)
 
@@ -332,8 +338,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=4176,
-  serialized_end=4261,
+  serialized_start=4539,
+  serialized_end=4624,
 )
 _sym_db.RegisterEnumDescriptor(_COMPONENT_QUALIFICATION_STATUS)
 
@@ -357,8 +363,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=4361,
-  serialized_end=4418,
+  serialized_start=4724,
+  serialized_end=4781,
 )
 _sym_db.RegisterEnumDescriptor(_COMPONENT_AMPLIFIER_FEATURE)
 
@@ -387,8 +393,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=4548,
-  serialized_end=4603,
+  serialized_start=4911,
+  serialized_end=4966,
 )
 _sym_db.RegisterEnumDescriptor(_COMPONENT_BATTERY_TECHNOLOGY)
 
@@ -422,11 +428,51 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=4876,
-  serialized_end=4945,
+  serialized_start=5302,
+  serialized_end=5371,
 )
 _sym_db.RegisterEnumDescriptor(_COMPONENT_STORAGE_STORAGETYPE)
 
+_COMPONENT_SUPPORTSTATUS = _descriptor.EnumDescriptor(
+  name='SupportStatus',
+  full_name='chromiumos.config.api.Component.SupportStatus',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='STATUS_UNKNOWN', index=0, number=0,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='STATUS_SUPPORTED', index=1, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='STATUS_DEPRECATED', index=2, number=2,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='STATUS_UNQUALIFIED', index=3, number=3,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='STATUS_UNSUPPORTED', index=4, number=4,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=5855,
+  serialized_end=5983,
+)
+_sym_db.RegisterEnumDescriptor(_COMPONENT_SUPPORTSTATUS)
+
 
 _COMPONENT_AVLID = _descriptor.Descriptor(
   name='AVLId',
@@ -462,8 +508,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1669,
-  serialized_end=1702,
+  serialized_start=1773,
+  serialized_end=1806,
 )
 
 _COMPONENT_INTERFACE_I2C = _descriptor.Descriptor(
@@ -500,8 +546,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1718,
-  serialized_end=1756,
+  serialized_start=1822,
+  serialized_end=1860,
 )
 
 _COMPONENT_INTERFACE_USB = _descriptor.Descriptor(
@@ -545,8 +591,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1758,
-  serialized_end=1822,
+  serialized_start=1862,
+  serialized_end=1926,
 )
 
 _COMPONENT_INTERFACE_PCI = _descriptor.Descriptor(
@@ -578,6 +624,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='class_id', full_name='chromiumos.config.api.Component.Interface.Pci.class_id', index=3,
+      number=4, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -590,8 +643,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1824,
-  serialized_end=1888,
+  serialized_start=1928,
+  serialized_end=2010,
 )
 
 _COMPONENT_INTERFACE = _descriptor.Descriptor(
@@ -614,8 +667,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1705,
-  serialized_end=1888,
+  serialized_start=1809,
+  serialized_end=2010,
 )
 
 _COMPONENT_SOC_FAMILY = _descriptor.Descriptor(
@@ -652,8 +705,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2053,
-  serialized_end=2140,
+  serialized_start=2175,
+  serialized_end=2262,
 )
 
 _COMPONENT_SOC = _descriptor.Descriptor(
@@ -706,8 +759,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1891,
-  serialized_end=2266,
+  serialized_start=2013,
+  serialized_end=2400,
 )
 
 _COMPONENT_MEMORY_PROFILE = _descriptor.Descriptor(
@@ -751,8 +804,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2366,
-  serialized_end=2478,
+  serialized_start=2500,
+  serialized_end=2612,
 )
 
 _COMPONENT_MEMORY = _descriptor.Descriptor(
@@ -790,8 +843,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2269,
-  serialized_end=2577,
+  serialized_start=2403,
+  serialized_end=2711,
 )
 
 _COMPONENT_BLUETOOTH = _descriptor.Descriptor(
@@ -821,8 +874,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2579,
-  serialized_end=2669,
+  serialized_start=2713,
+  serialized_end=2803,
 )
 
 _COMPONENT_CAMERA = _descriptor.Descriptor(
@@ -880,8 +933,8 @@
       create_key=_descriptor._internal_create_key,
     fields=[]),
   ],
-  serialized_start=2672,
-  serialized_end=3075,
+  serialized_start=2806,
+  serialized_end=3209,
 )
 
 _COMPONENT_DISPLAYPANEL_PROPERTIES = _descriptor.Descriptor(
@@ -927,6 +980,41 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='min_visible_backlight_level', full_name='chromiumos.config.api.Component.DisplayPanel.Properties.min_visible_backlight_level', index=5,
+      number=6, type=13, cpp_type=3, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='turn_off_screen_timeout_ms', full_name='chromiumos.config.api.Component.DisplayPanel.Properties.turn_off_screen_timeout_ms', index=6,
+      number=7, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='no_als_battery_brightness', full_name='chromiumos.config.api.Component.DisplayPanel.Properties.no_als_battery_brightness', index=7,
+      number=8, type=1, cpp_type=5, label=1,
+      has_default_value=False, default_value=float(0),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='no_als_ac_brightness', full_name='chromiumos.config.api.Component.DisplayPanel.Properties.no_als_ac_brightness', index=8,
+      number=9, type=1, cpp_type=5, label=1,
+      has_default_value=False, default_value=float(0),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='als_steps', full_name='chromiumos.config.api.Component.DisplayPanel.Properties.als_steps', index=9,
+      number=10, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -939,8 +1027,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3193,
-  serialized_end=3366,
+  serialized_start=3327,
+  serialized_end=3729,
 )
 
 _COMPONENT_DISPLAYPANEL = _descriptor.Descriptor(
@@ -978,8 +1066,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3078,
-  serialized_end=3407,
+  serialized_start=3212,
+  serialized_end=3770,
 )
 
 _COMPONENT_TOUCH = _descriptor.Descriptor(
@@ -1045,8 +1133,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3410,
-  serialized_end=3696,
+  serialized_start=3773,
+  serialized_end=4059,
 )
 
 _COMPONENT_WIFI = _descriptor.Descriptor(
@@ -1089,8 +1177,8 @@
       create_key=_descriptor._internal_create_key,
     fields=[]),
   ],
-  serialized_start=3699,
-  serialized_end=4027,
+  serialized_start=4062,
+  serialized_end=4390,
 )
 
 _COMPONENT_QUALIFICATION = _descriptor.Descriptor(
@@ -1128,8 +1216,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4030,
-  serialized_end=4261,
+  serialized_start=4393,
+  serialized_end=4624,
 )
 
 _COMPONENT_AMPLIFIER = _descriptor.Descriptor(
@@ -1167,8 +1255,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4264,
-  serialized_end=4418,
+  serialized_start=4627,
+  serialized_end=4781,
 )
 
 _COMPONENT_AUDIOCODEC = _descriptor.Descriptor(
@@ -1198,8 +1286,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4420,
-  serialized_end=4446,
+  serialized_start=4783,
+  serialized_end=4809,
 )
 
 _COMPONENT_BATTERY = _descriptor.Descriptor(
@@ -1237,8 +1325,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4449,
-  serialized_end=4603,
+  serialized_start=4812,
+  serialized_end=4966,
 )
 
 _COMPONENT_FLASHCHIP = _descriptor.Descriptor(
@@ -1268,8 +1356,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4605,
-  serialized_end=4637,
+  serialized_start=4968,
+  serialized_end=5000,
 )
 
 _COMPONENT_EMBEDDEDCONTROLLER = _descriptor.Descriptor(
@@ -1299,8 +1387,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4639,
-  serialized_end=4680,
+  serialized_start=5002,
+  serialized_end=5043,
 )
 
 _COMPONENT_STORAGE = _descriptor.Descriptor(
@@ -1367,6 +1455,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='pci', full_name='chromiumos.config.api.Component.Storage.pci', index=8,
+      number=9, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -1379,9 +1474,14 @@
   syntax='proto3',
   extension_ranges=[],
   oneofs=[
+    _descriptor.OneofDescriptor(
+      name='interface', full_name='chromiumos.config.api.Component.Storage.interface',
+      index=0, containing_type=None,
+      create_key=_descriptor._internal_create_key,
+    fields=[]),
   ],
-  serialized_start=4683,
-  serialized_end=4945,
+  serialized_start=5046,
+  serialized_end=5384,
 )
 
 _COMPONENT_TPM = _descriptor.Descriptor(
@@ -1418,8 +1518,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4947,
-  serialized_end=4996,
+  serialized_start=5386,
+  serialized_end=5435,
 )
 
 _COMPONENT_STYLUS = _descriptor.Descriptor(
@@ -1461,8 +1561,8 @@
       create_key=_descriptor._internal_create_key,
     fields=[]),
   ],
-  serialized_start=4999,
-  serialized_end=5146,
+  serialized_start=5438,
+  serialized_end=5585,
 )
 
 _COMPONENT_DISPLAYPORTCONVERTER = _descriptor.Descriptor(
@@ -1492,8 +1592,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5148,
-  serialized_end=5184,
+  serialized_start=5587,
+  serialized_end=5623,
 )
 
 _COMPONENT_CELLULAR = _descriptor.Descriptor(
@@ -1528,8 +1628,60 @@
       create_key=_descriptor._internal_create_key,
     fields=[]),
   ],
-  serialized_start=5186,
-  serialized_end=5272,
+  serialized_start=5625,
+  serialized_end=5711,
+)
+
+_COMPONENT_ALSSTEP = _descriptor.Descriptor(
+  name='AlsStep',
+  full_name='chromiumos.config.api.Component.AlsStep',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='ac_backlight_percent', full_name='chromiumos.config.api.Component.AlsStep.ac_backlight_percent', index=0,
+      number=1, type=1, cpp_type=5, label=1,
+      has_default_value=False, default_value=float(0),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='battery_backlight_percent', full_name='chromiumos.config.api.Component.AlsStep.battery_backlight_percent', index=1,
+      number=2, type=1, cpp_type=5, label=1,
+      has_default_value=False, default_value=float(0),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='lux_decrease_threshold', full_name='chromiumos.config.api.Component.AlsStep.lux_decrease_threshold', index=2,
+      number=3, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='lux_increase_threshold', full_name='chromiumos.config.api.Component.AlsStep.lux_increase_threshold', index=3,
+      number=4, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=5714,
+  serialized_end=5852,
 )
 
 _COMPONENT = _descriptor.Descriptor(
@@ -1590,140 +1742,147 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='soc', full_name='chromiumos.config.api.Component.soc', index=7,
+      name='support_status', full_name='chromiumos.config.api.Component.support_status', index=7,
+      number=28, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='soc', full_name='chromiumos.config.api.Component.soc', index=8,
       number=2, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='memory', full_name='chromiumos.config.api.Component.memory', index=8,
+      name='memory', full_name='chromiumos.config.api.Component.memory', index=9,
       number=3, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='bluetooth', full_name='chromiumos.config.api.Component.bluetooth', index=9,
+      name='bluetooth', full_name='chromiumos.config.api.Component.bluetooth', index=10,
       number=4, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='camera', full_name='chromiumos.config.api.Component.camera', index=10,
+      name='camera', full_name='chromiumos.config.api.Component.camera', index=11,
       number=5, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='touchscreen', full_name='chromiumos.config.api.Component.touchscreen', index=11,
+      name='touchscreen', full_name='chromiumos.config.api.Component.touchscreen', index=12,
       number=6, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='wifi', full_name='chromiumos.config.api.Component.wifi', index=12,
+      name='wifi', full_name='chromiumos.config.api.Component.wifi', index=13,
       number=7, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='touchpad', full_name='chromiumos.config.api.Component.touchpad', index=13,
+      name='touchpad', full_name='chromiumos.config.api.Component.touchpad', index=14,
       number=10, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='display_panel', full_name='chromiumos.config.api.Component.display_panel', index=14,
+      name='display_panel', full_name='chromiumos.config.api.Component.display_panel', index=15,
       number=11, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='audio_codec', full_name='chromiumos.config.api.Component.audio_codec', index=15,
+      name='audio_codec', full_name='chromiumos.config.api.Component.audio_codec', index=16,
       number=12, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='battery', full_name='chromiumos.config.api.Component.battery', index=16,
+      name='battery', full_name='chromiumos.config.api.Component.battery', index=17,
       number=13, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='ec_flash_chip', full_name='chromiumos.config.api.Component.ec_flash_chip', index=17,
+      name='ec_flash_chip', full_name='chromiumos.config.api.Component.ec_flash_chip', index=18,
       number=14, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='system_flash_chip', full_name='chromiumos.config.api.Component.system_flash_chip', index=18,
+      name='system_flash_chip', full_name='chromiumos.config.api.Component.system_flash_chip', index=19,
       number=15, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='ec', full_name='chromiumos.config.api.Component.ec', index=19,
+      name='ec', full_name='chromiumos.config.api.Component.ec', index=20,
       number=16, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='storage', full_name='chromiumos.config.api.Component.storage', index=20,
+      name='storage', full_name='chromiumos.config.api.Component.storage', index=21,
       number=17, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='tpm', full_name='chromiumos.config.api.Component.tpm', index=21,
+      name='tpm', full_name='chromiumos.config.api.Component.tpm', index=22,
       number=18, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='usb_host', full_name='chromiumos.config.api.Component.usb_host', index=22,
+      name='usb_host', full_name='chromiumos.config.api.Component.usb_host', index=23,
       number=19, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='stylus', full_name='chromiumos.config.api.Component.stylus', index=23,
+      name='stylus', full_name='chromiumos.config.api.Component.stylus', index=24,
       number=23, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='amplifier', full_name='chromiumos.config.api.Component.amplifier', index=24,
+      name='amplifier', full_name='chromiumos.config.api.Component.amplifier', index=25,
       number=24, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='dp_converter', full_name='chromiumos.config.api.Component.dp_converter', index=25,
+      name='dp_converter', full_name='chromiumos.config.api.Component.dp_converter', index=26,
       number=26, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='cellular', full_name='chromiumos.config.api.Component.cellular', index=26,
+      name='cellular', full_name='chromiumos.config.api.Component.cellular', index=27,
       number=27, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
@@ -1732,8 +1891,9 @@
   ],
   extensions=[
   ],
-  nested_types=[_COMPONENT_AVLID, _COMPONENT_INTERFACE, _COMPONENT_SOC, _COMPONENT_MEMORY, _COMPONENT_BLUETOOTH, _COMPONENT_CAMERA, _COMPONENT_DISPLAYPANEL, _COMPONENT_TOUCH, _COMPONENT_WIFI, _COMPONENT_QUALIFICATION, _COMPONENT_AMPLIFIER, _COMPONENT_AUDIOCODEC, _COMPONENT_BATTERY, _COMPONENT_FLASHCHIP, _COMPONENT_EMBEDDEDCONTROLLER, _COMPONENT_STORAGE, _COMPONENT_TPM, _COMPONENT_STYLUS, _COMPONENT_DISPLAYPORTCONVERTER, _COMPONENT_CELLULAR, ],
+  nested_types=[_COMPONENT_AVLID, _COMPONENT_INTERFACE, _COMPONENT_SOC, _COMPONENT_MEMORY, _COMPONENT_BLUETOOTH, _COMPONENT_CAMERA, _COMPONENT_DISPLAYPANEL, _COMPONENT_TOUCH, _COMPONENT_WIFI, _COMPONENT_QUALIFICATION, _COMPONENT_AMPLIFIER, _COMPONENT_AUDIOCODEC, _COMPONENT_BATTERY, _COMPONENT_FLASHCHIP, _COMPONENT_EMBEDDEDCONTROLLER, _COMPONENT_STORAGE, _COMPONENT_TPM, _COMPONENT_STYLUS, _COMPONENT_DISPLAYPORTCONVERTER, _COMPONENT_CELLULAR, _COMPONENT_ALSSTEP, ],
   enum_types=[
+    _COMPONENT_SUPPORTSTATUS,
   ],
   serialized_options=None,
   is_extendable=False,
@@ -1746,8 +1906,8 @@
       create_key=_descriptor._internal_create_key,
     fields=[]),
   ],
-  serialized_start=147,
-  serialized_end=5280,
+  serialized_start=179,
+  serialized_end=5991,
 )
 
 _COMPONENT_AVLID.containing_type = _COMPONENT
@@ -1783,6 +1943,8 @@
   _COMPONENT_CAMERA.fields_by_name['pci'])
 _COMPONENT_CAMERA.fields_by_name['pci'].containing_oneof = _COMPONENT_CAMERA.oneofs_by_name['interface']
 _COMPONENT_DISPLAYPANEL_PROPERTIES.fields_by_name['features'].enum_type = _COMPONENT_DISPLAYPANEL_FEATURE
+_COMPONENT_DISPLAYPANEL_PROPERTIES.fields_by_name['turn_off_screen_timeout_ms'].message_type = google_dot_protobuf_dot_wrappers__pb2._UINT32VALUE
+_COMPONENT_DISPLAYPANEL_PROPERTIES.fields_by_name['als_steps'].message_type = _COMPONENT_ALSSTEP
 _COMPONENT_DISPLAYPANEL_PROPERTIES.containing_type = _COMPONENT_DISPLAYPANEL
 _COMPONENT_DISPLAYPANEL.fields_by_name['properties'].message_type = _COMPONENT_DISPLAYPANEL_PROPERTIES
 _COMPONENT_DISPLAYPANEL.containing_type = _COMPONENT
@@ -1812,8 +1974,12 @@
 _COMPONENT_FLASHCHIP.containing_type = _COMPONENT
 _COMPONENT_EMBEDDEDCONTROLLER.containing_type = _COMPONENT
 _COMPONENT_STORAGE.fields_by_name['type'].enum_type = _COMPONENT_STORAGE_STORAGETYPE
+_COMPONENT_STORAGE.fields_by_name['pci'].message_type = _COMPONENT_INTERFACE_PCI
 _COMPONENT_STORAGE.containing_type = _COMPONENT
 _COMPONENT_STORAGE_STORAGETYPE.containing_type = _COMPONENT_STORAGE
+_COMPONENT_STORAGE.oneofs_by_name['interface'].fields.append(
+  _COMPONENT_STORAGE.fields_by_name['pci'])
+_COMPONENT_STORAGE.fields_by_name['pci'].containing_oneof = _COMPONENT_STORAGE.oneofs_by_name['interface']
 _COMPONENT_TPM.containing_type = _COMPONENT
 _COMPONENT_STYLUS.fields_by_name['usb'].message_type = _COMPONENT_INTERFACE_USB
 _COMPONENT_STYLUS.fields_by_name['i2c'].message_type = _COMPONENT_INTERFACE_I2C
@@ -1830,9 +1996,11 @@
 _COMPONENT_CELLULAR.oneofs_by_name['interface'].fields.append(
   _COMPONENT_CELLULAR.fields_by_name['usb'])
 _COMPONENT_CELLULAR.fields_by_name['usb'].containing_oneof = _COMPONENT_CELLULAR.oneofs_by_name['interface']
+_COMPONENT_ALSSTEP.containing_type = _COMPONENT
 _COMPONENT.fields_by_name['id'].message_type = chromiumos_dot_config_dot_api_dot_component__id__pb2._COMPONENTID
 _COMPONENT.fields_by_name['manufacturer_id'].message_type = chromiumos_dot_config_dot_api_dot_partner__id__pb2._PARTNERID
 _COMPONENT.fields_by_name['avl_id'].message_type = _COMPONENT_AVLID
+_COMPONENT.fields_by_name['support_status'].enum_type = _COMPONENT_SUPPORTSTATUS
 _COMPONENT.fields_by_name['soc'].message_type = _COMPONENT_SOC
 _COMPONENT.fields_by_name['memory'].message_type = _COMPONENT_MEMORY
 _COMPONENT.fields_by_name['bluetooth'].message_type = _COMPONENT_BLUETOOTH
@@ -1853,6 +2021,7 @@
 _COMPONENT.fields_by_name['amplifier'].message_type = _COMPONENT_AMPLIFIER
 _COMPONENT.fields_by_name['dp_converter'].message_type = _COMPONENT_DISPLAYPORTCONVERTER
 _COMPONENT.fields_by_name['cellular'].message_type = _COMPONENT_CELLULAR
+_COMPONENT_SUPPORTSTATUS.containing_type = _COMPONENT
 _COMPONENT.oneofs_by_name['type'].fields.append(
   _COMPONENT.fields_by_name['soc'])
 _COMPONENT.fields_by_name['soc'].containing_oneof = _COMPONENT.oneofs_by_name['type']
@@ -2099,6 +2268,13 @@
     # @@protoc_insertion_point(class_scope:chromiumos.config.api.Component.Cellular)
     })
   ,
+
+  'AlsStep' : _reflection.GeneratedProtocolMessageType('AlsStep', (_message.Message,), {
+    'DESCRIPTOR' : _COMPONENT_ALSSTEP,
+    '__module__' : 'chromiumos.config.api.component_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.config.api.Component.AlsStep)
+    })
+  ,
   'DESCRIPTOR' : _COMPONENT,
   '__module__' : 'chromiumos.config.api.component_pb2'
   # @@protoc_insertion_point(class_scope:chromiumos.config.api.Component)
@@ -2130,6 +2306,7 @@
 _sym_db.RegisterMessage(Component.Stylus)
 _sym_db.RegisterMessage(Component.DisplayPortConverter)
 _sym_db.RegisterMessage(Component.Cellular)
+_sym_db.RegisterMessage(Component.AlsStep)
 
 
 DESCRIPTOR._options = None
diff --git a/api/gen/chromiumos/config/api/design_pb2.py b/api/gen/chromiumos/config/api/design_pb2.py
index d7ee7d9..56115ee 100644
--- a/api/gen/chromiumos/config/api/design_pb2.py
+++ b/api/gen/chromiumos/config/api/design_pb2.py
@@ -26,7 +26,7 @@
   syntax='proto3',
   serialized_options=b'Z(go.chromium.org/chromiumos/config/go/api',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n\"chromiumos/config/api/design.proto\x12\x15\x63hromiumos.config.api\x1a,chromiumos/config/api/design_config_id.proto\x1a%chromiumos/config/api/design_id.proto\x1a-chromiumos/config/api/hardware_topology.proto\x1a&chromiumos/config/api/partner_id.proto\x1a&chromiumos/config/api/program_id.proto\x1a$chromiumos/config/api/topology.proto\x1a=chromiumos/config/public_replication/public_replication.proto\"\xb6\x08\n\x06\x44\x65sign\x12S\n\x12public_replication\x18\x07 \x01(\x0b\x32\x37.chromiumos.config.public_replication.PublicReplication\x12+\n\x02id\x18\x01 \x01(\x0b\x32\x1f.chromiumos.config.api.DesignId\x12\x34\n\nprogram_id\x18\x02 \x01(\x0b\x32 .chromiumos.config.api.ProgramId\x12\x30\n\x06odm_id\x18\x03 \x01(\x0b\x32 .chromiumos.config.api.PartnerId\x12\x0c\n\x04name\x18\x04 \x01(\t\x12G\n\x0e\x62oard_id_phase\x18\x05 \x03(\x0b\x32/.chromiumos.config.api.Design.BoardIdPhaseEntry\x12\x35\n\x07\x63onfigs\x18\x06 \x03(\x0b\x32$.chromiumos.config.api.Design.Config\x12@\n\nssfc_value\x18\x08 \x03(\x0b\x32,.chromiumos.config.api.Design.SsfcValueEntry\x1a\x33\n\x11\x42oardIdPhaseEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\x30\n\x0eSsfcValueEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\xfa\x03\n\x06\x43onfig\x12S\n\x12public_replication\x18\x05 \x01(\x0b\x32\x37.chromiumos.config.public_replication.PublicReplication\x12\x31\n\x02id\x18\x01 \x01(\x0b\x32%.chromiumos.config.api.DesignConfigId\x12\x42\n\x11hardware_topology\x18\x02 \x01(\x0b\x32\'.chromiumos.config.api.HardwareTopology\x12\x42\n\x11hardware_features\x18\x03 \x01(\x0b\x32\'.chromiumos.config.api.HardwareFeatures\x1a\xd3\x01\n\nConstraint\x12\x44\n\x05level\x18\x01 \x01(\x0e\x32\x35.chromiumos.config.api.Design.Config.Constraint.Level\x12\x39\n\x08\x66\x65\x61tures\x18\x02 \x01(\x0b\x32\'.chromiumos.config.api.HardwareFeatures\"D\n\x05Level\x12\x10\n\x0cTYPE_UNKNOWN\x10\x00\x12\x0c\n\x08REQUIRED\x10\x01\x12\r\n\tPREFERRED\x10\x02\x12\x0c\n\x08OPTIONAL\x10\x03J\x04\x08\x04\x10\x05J\x04\x08\x07\x10\x08J\x04\x08\t\x10\nR\x08platformB*Z(go.chromium.org/chromiumos/config/go/apib\x06proto3'
+  serialized_pb=b'\n\"chromiumos/config/api/design.proto\x12\x15\x63hromiumos.config.api\x1a,chromiumos/config/api/design_config_id.proto\x1a%chromiumos/config/api/design_id.proto\x1a-chromiumos/config/api/hardware_topology.proto\x1a&chromiumos/config/api/partner_id.proto\x1a&chromiumos/config/api/program_id.proto\x1a$chromiumos/config/api/topology.proto\x1a=chromiumos/config/public_replication/public_replication.proto\"\xaf\t\n\x06\x44\x65sign\x12S\n\x12public_replication\x18\x07 \x01(\x0b\x32\x37.chromiumos.config.public_replication.PublicReplication\x12+\n\x02id\x18\x01 \x01(\x0b\x32\x1f.chromiumos.config.api.DesignId\x12\x34\n\nprogram_id\x18\x02 \x01(\x0b\x32 .chromiumos.config.api.ProgramId\x12\x30\n\x06odm_id\x18\x03 \x01(\x0b\x32 .chromiumos.config.api.PartnerId\x12\x0c\n\x04name\x18\x04 \x01(\t\x12G\n\x0e\x62oard_id_phase\x18\x05 \x03(\x0b\x32/.chromiumos.config.api.Design.BoardIdPhaseEntry\x12\x35\n\x07\x63onfigs\x18\x06 \x03(\x0b\x32$.chromiumos.config.api.Design.Config\x12@\n\nssfc_value\x18\x08 \x03(\x0b\x32,.chromiumos.config.api.Design.SsfcValueEntry\x12=\n\x0b\x63ustom_type\x18\n \x01(\x0e\x32(.chromiumos.config.api.Design.CustomType\x1a\x33\n\x11\x42oardIdPhaseEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\x30\n\x0eSsfcValueEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\xfa\x03\n\x06\x43onfig\x12S\n\x12public_replication\x18\x05 \x01(\x0b\x32\x37.chromiumos.config.public_replication.PublicReplication\x12\x31\n\x02id\x18\x01 \x01(\x0b\x32%.chromiumos.config.api.DesignConfigId\x12\x42\n\x11hardware_topology\x18\x02 \x01(\x0b\x32\'.chromiumos.config.api.HardwareTopology\x12\x42\n\x11hardware_features\x18\x03 \x01(\x0b\x32\'.chromiumos.config.api.HardwareFeatures\x1a\xd3\x01\n\nConstraint\x12\x44\n\x05level\x18\x01 \x01(\x0e\x32\x35.chromiumos.config.api.Design.Config.Constraint.Level\x12\x39\n\x08\x66\x65\x61tures\x18\x02 \x01(\x0b\x32\'.chromiumos.config.api.HardwareFeatures\"D\n\x05Level\x12\x10\n\x0cTYPE_UNKNOWN\x10\x00\x12\x0c\n\x08REQUIRED\x10\x01\x12\r\n\tPREFERRED\x10\x02\x12\x0c\n\x08OPTIONAL\x10\x03J\x04\x08\x04\x10\x05J\x04\x08\x07\x10\x08\"8\n\nCustomType\x12\r\n\tNO_CUSTOM\x10\x00\x12\x0e\n\nWHITELABEL\x10\x01\x12\x0b\n\x07REBRAND\x10\x02J\x04\x08\t\x10\nR\x08platformB*Z(go.chromium.org/chromiumos/config/go/apib\x06proto3'
   ,
   dependencies=[chromiumos_dot_config_dot_api_dot_design__config__id__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_design__id__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_hardware__topology__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_partner__id__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_program__id__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_topology__pb2.DESCRIPTOR,chromiumos_dot_config_dot_public__replication_dot_public__replication__pb2.DESCRIPTOR,])
 
@@ -62,11 +62,41 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1357,
-  serialized_end=1425,
+  serialized_start=1420,
+  serialized_end=1488,
 )
 _sym_db.RegisterEnumDescriptor(_DESIGN_CONFIG_CONSTRAINT_LEVEL)
 
+_DESIGN_CUSTOMTYPE = _descriptor.EnumDescriptor(
+  name='CustomType',
+  full_name='chromiumos.config.api.Design.CustomType',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='NO_CUSTOM', index=0, number=0,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='WHITELABEL', index=1, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='REBRAND', index=2, number=2,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=1502,
+  serialized_end=1558,
+)
+_sym_db.RegisterEnumDescriptor(_DESIGN_CUSTOMTYPE)
+
 
 _DESIGN_BOARDIDPHASEENTRY = _descriptor.Descriptor(
   name='BoardIdPhaseEntry',
@@ -102,8 +132,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=827,
-  serialized_end=878,
+  serialized_start=890,
+  serialized_end=941,
 )
 
 _DESIGN_SSFCVALUEENTRY = _descriptor.Descriptor(
@@ -140,8 +170,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=880,
-  serialized_end=928,
+  serialized_start=943,
+  serialized_end=991,
 )
 
 _DESIGN_CONFIG_CONSTRAINT = _descriptor.Descriptor(
@@ -179,8 +209,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1214,
-  serialized_end=1425,
+  serialized_start=1277,
+  serialized_end=1488,
 )
 
 _DESIGN_CONFIG = _descriptor.Descriptor(
@@ -231,8 +261,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=931,
-  serialized_end=1437,
+  serialized_start=994,
+  serialized_end=1500,
 )
 
 _DESIGN = _descriptor.Descriptor(
@@ -299,11 +329,19 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='custom_type', full_name='chromiumos.config.api.Design.custom_type', index=8,
+      number=10, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
   nested_types=[_DESIGN_BOARDIDPHASEENTRY, _DESIGN_SSFCVALUEENTRY, _DESIGN_CONFIG, ],
   enum_types=[
+    _DESIGN_CUSTOMTYPE,
   ],
   serialized_options=None,
   is_extendable=False,
@@ -312,7 +350,7 @@
   oneofs=[
   ],
   serialized_start=375,
-  serialized_end=1453,
+  serialized_end=1574,
 )
 
 _DESIGN_BOARDIDPHASEENTRY.containing_type = _DESIGN
@@ -333,6 +371,8 @@
 _DESIGN.fields_by_name['board_id_phase'].message_type = _DESIGN_BOARDIDPHASEENTRY
 _DESIGN.fields_by_name['configs'].message_type = _DESIGN_CONFIG
 _DESIGN.fields_by_name['ssfc_value'].message_type = _DESIGN_SSFCVALUEENTRY
+_DESIGN.fields_by_name['custom_type'].enum_type = _DESIGN_CUSTOMTYPE
+_DESIGN_CUSTOMTYPE.containing_type = _DESIGN
 DESCRIPTOR.message_types_by_name['Design'] = _DESIGN
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
diff --git a/api/gen/chromiumos/config/api/hardware_topology_pb2.py b/api/gen/chromiumos/config/api/hardware_topology_pb2.py
index cc7200b..1b48598 100644
--- a/api/gen/chromiumos/config/api/hardware_topology_pb2.py
+++ b/api/gen/chromiumos/config/api/hardware_topology_pb2.py
@@ -20,7 +20,7 @@
   syntax='proto3',
   serialized_options=b'Z(go.chromium.org/chromiumos/config/go/api',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n-chromiumos/config/api/hardware_topology.proto\x12\x15\x63hromiumos.config.api\x1a$chromiumos/config/api/topology.proto\"\xfa\n\n\x10HardwareTopology\x12/\n\x06screen\x18\x01 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x34\n\x0b\x66orm_factor\x18\x02 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12.\n\x05\x61udio\x18\x03 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12/\n\x06stylus\x18\x04 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x31\n\x08keyboard\x18\x05 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x30\n\x07thermal\x18\x06 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12/\n\x06\x63\x61mera\x18\x07 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12M\n$accelerometer_gyroscope_magnetometer\x18\x08 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x34\n\x0b\x66ingerprint\x18\t \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x39\n\x10proximity_sensor\x18\n \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x37\n\x0e\x64\x61ughter_board\x18\x0b \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12=\n\x14non_volatile_storage\x18\x0c \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12,\n\x03ram\x18\r \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12-\n\x04wifi\x18\x0e \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x32\n\tlte_board\x18\x0f \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x32\n\tsd_reader\x18\x10 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x38\n\x0fmotherboard_usb\x18\x11 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x32\n\tbluetooth\x18\x12 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x33\n\nbarreljack\x18\x13 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x35\n\x0cpower_button\x18\x14 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x36\n\rvolume_button\x18\x15 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12+\n\x02\x65\x63\x18\x16 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12.\n\x05touch\x18\x17 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12,\n\x03tpm\x18\x18 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12?\n\x16microphone_mute_switch\x18\x19 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12-\n\x04hdmi\x18\x1a \x01(\x0b\x32\x1f.chromiumos.config.api.TopologyB*Z(go.chromium.org/chromiumos/config/go/apib\x06proto3'
+  serialized_pb=b'\n-chromiumos/config/api/hardware_topology.proto\x12\x15\x63hromiumos.config.api\x1a$chromiumos/config/api/topology.proto\"\xc9\x0c\n\x10HardwareTopology\x12/\n\x06screen\x18\x01 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x34\n\x0b\x66orm_factor\x18\x02 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12.\n\x05\x61udio\x18\x03 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12/\n\x06stylus\x18\x04 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x31\n\x08keyboard\x18\x05 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x30\n\x07thermal\x18\x06 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12/\n\x06\x63\x61mera\x18\x07 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12M\n$accelerometer_gyroscope_magnetometer\x18\x08 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x34\n\x0b\x66ingerprint\x18\t \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x39\n\x10proximity_sensor\x18\n \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x37\n\x0e\x64\x61ughter_board\x18\x0b \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12=\n\x14non_volatile_storage\x18\x0c \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12,\n\x03ram\x18\r \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12-\n\x04wifi\x18\x0e \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x37\n\x0e\x63\x65llular_board\x18\x0f \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x32\n\tsd_reader\x18\x10 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x38\n\x0fmotherboard_usb\x18\x11 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x32\n\tbluetooth\x18\x12 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x33\n\nbarreljack\x18\x13 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x35\n\x0cpower_button\x18\x14 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x36\n\rvolume_button\x18\x15 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12+\n\x02\x65\x63\x18\x16 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12.\n\x05touch\x18\x17 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12,\n\x03tpm\x18\x18 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12?\n\x16microphone_mute_switch\x18\x19 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12-\n\x04hdmi\x18\x1a \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12,\n\x03hps\x18\x1b \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x35\n\x0c\x64p_converter\x18\x1c \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12,\n\x03poe\x18\x1d \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x35\n\x0cpower_supply\x18\x1e \x01(\x0b\x32\x1f.chromiumos.config.api.TopologyB*Z(go.chromium.org/chromiumos/config/go/apib\x06proto3'
   ,
   dependencies=[chromiumos_dot_config_dot_api_dot_topology__pb2.DESCRIPTOR,])
 
@@ -134,7 +134,7 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='lte_board', full_name='chromiumos.config.api.HardwareTopology.lte_board', index=14,
+      name='cellular_board', full_name='chromiumos.config.api.HardwareTopology.cellular_board', index=14,
       number=15, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
@@ -217,6 +217,34 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='hps', full_name='chromiumos.config.api.HardwareTopology.hps', index=26,
+      number=27, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='dp_converter', full_name='chromiumos.config.api.HardwareTopology.dp_converter', index=27,
+      number=28, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='poe', full_name='chromiumos.config.api.HardwareTopology.poe', index=28,
+      number=29, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='power_supply', full_name='chromiumos.config.api.HardwareTopology.power_supply', index=29,
+      number=30, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -230,7 +258,7 @@
   oneofs=[
   ],
   serialized_start=111,
-  serialized_end=1513,
+  serialized_end=1720,
 )
 
 _HARDWARETOPOLOGY.fields_by_name['screen'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
@@ -247,7 +275,7 @@
 _HARDWARETOPOLOGY.fields_by_name['non_volatile_storage'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
 _HARDWARETOPOLOGY.fields_by_name['ram'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
 _HARDWARETOPOLOGY.fields_by_name['wifi'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
-_HARDWARETOPOLOGY.fields_by_name['lte_board'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
+_HARDWARETOPOLOGY.fields_by_name['cellular_board'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
 _HARDWARETOPOLOGY.fields_by_name['sd_reader'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
 _HARDWARETOPOLOGY.fields_by_name['motherboard_usb'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
 _HARDWARETOPOLOGY.fields_by_name['bluetooth'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
@@ -259,6 +287,10 @@
 _HARDWARETOPOLOGY.fields_by_name['tpm'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
 _HARDWARETOPOLOGY.fields_by_name['microphone_mute_switch'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
 _HARDWARETOPOLOGY.fields_by_name['hdmi'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
+_HARDWARETOPOLOGY.fields_by_name['hps'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
+_HARDWARETOPOLOGY.fields_by_name['dp_converter'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
+_HARDWARETOPOLOGY.fields_by_name['poe'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
+_HARDWARETOPOLOGY.fields_by_name['power_supply'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
 DESCRIPTOR.message_types_by_name['HardwareTopology'] = _HARDWARETOPOLOGY
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
diff --git a/api/gen/chromiumos/config/api/program_pb2.py b/api/gen/chromiumos/config/api/program_pb2.py
index c9e8f45..39df3d7 100644
--- a/api/gen/chromiumos/config/api/program_pb2.py
+++ b/api/gen/chromiumos/config/api/program_pb2.py
@@ -16,6 +16,7 @@
 from chromite.api.gen.chromiumos.config.api import design_id_pb2 as chromiumos_dot_config_dot_api_dot_design__id__pb2
 from chromite.api.gen.chromiumos.config.api import device_brand_id_pb2 as chromiumos_dot_config_dot_api_dot_device__brand__id__pb2
 from chromite.api.gen.chromiumos.config.api import program_id_pb2 as chromiumos_dot_config_dot_api_dot_program__id__pb2
+from chromite.api.gen.chromiumos.config.api import topology_pb2 as chromiumos_dot_config_dot_api_dot_topology__pb2
 from chromite.api.gen.chromiumos.config.public_replication import public_replication_pb2 as chromiumos_dot_config_dot_public__replication_dot_public__replication__pb2
 
 
@@ -25,9 +26,9 @@
   syntax='proto3',
   serialized_options=b'Z(go.chromium.org/chromiumos/config/go/api',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n#chromiumos/config/api/program.proto\x12\x15\x63hromiumos.config.api\x1a%chromiumos/config/api/component.proto\x1a\"chromiumos/config/api/design.proto\x1a%chromiumos/config/api/design_id.proto\x1a+chromiumos/config/api/device_brand_id.proto\x1a&chromiumos/config/api/program_id.proto\x1a=chromiumos/config/public_replication/public_replication.proto\":\n\x1c\x46irmwareConfigurationSegment\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04mask\x18\x02 \x01(\r\"k\n\x15\x44\x65signConfigIdSegment\x12\x32\n\tdesign_id\x18\x01 \x01(\x0b\x32\x1f.chromiumos.config.api.DesignId\x12\x0e\n\x06min_id\x18\x02 \x01(\r\x12\x0e\n\x06max_id\x18\x03 \x01(\r\"\xa2\x01\n\x12\x44\x65viceSignerConfig\x12\x38\n\x08\x62rand_id\x18\x01 \x01(\x0b\x32$.chromiumos.config.api.DeviceBrandIdH\x00\x12\x34\n\tdesign_id\x18\x03 \x01(\x0b\x32\x1f.chromiumos.config.api.DesignIdH\x00\x12\x0e\n\x06key_id\x18\x02 \x01(\tB\x0c\n\nidentifier\"\x86\x0b\n\x07Program\x12S\n\x12public_replication\x18\x08 \x01(\x0b\x32\x37.chromiumos.config.public_replication.PublicReplication\x12,\n\x02id\x18\x01 \x01(\x0b\x32 .chromiumos.config.api.ProgramId\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x1b\n\x13mosys_platform_name\x18\n \x01(\t\x12\x39\n\x08platform\x18\x0b \x01(\x0b\x32\'.chromiumos.config.api.Program.Platform\x12R\n\x19\x64\x65sign_config_constraints\x18\x03 \x03(\x0b\x32/.chromiumos.config.api.Design.Config.Constraint\x12G\n\x0f\x63omponent_quals\x18\x04 \x03(\x0b\x32..chromiumos.config.api.Component.Qualification\x12\\\n\x1f\x66irmware_configuration_segments\x18\x05 \x03(\x0b\x32\x33.chromiumos.config.api.FirmwareConfigurationSegment\x12J\n\rssfc_segments\x18\t \x03(\x0b\x32\x33.chromiumos.config.api.FirmwareConfigurationSegment\x12O\n\x19\x64\x65sign_config_id_segments\x18\x07 \x03(\x0b\x32,.chromiumos.config.api.DesignConfigIdSegment\x12H\n\x15\x64\x65vice_signer_configs\x18\x06 \x03(\x0b\x32).chromiumos.config.api.DeviceSignerConfig\x1a\xaf\x05\n\x08Platform\x12\x12\n\nsoc_family\x18\x01 \x01(\t\x12>\n\x08soc_arch\x18\x02 \x01(\x0e\x32,.chromiumos.config.api.Program.Platform.Arch\x12\x12\n\ngpu_family\x18\x03 \x01(\t\x12J\n\rgraphics_apis\x18\x04 \x03(\x0e\x32\x33.chromiumos.config.api.Program.Platform.GraphicsApi\x12S\n\x0cvideo_codecs\x18\x05 \x03(\x0e\x32=.chromiumos.config.api.Program.Platform.AcceleratedVideoCodec\"A\n\x04\x41rch\x12\x10\n\x0c\x41RCH_UNKNOWN\x10\x00\x12\x07\n\x03X86\x10\x01\x12\n\n\x06X86_64\x10\x02\x12\x07\n\x03\x41RM\x10\x03\x12\t\n\x05\x41RM64\x10\x04\"\xf6\x01\n\x15\x41\x63\x63\x65leratedVideoCodec\x12\x13\n\x0f\x43ODEC_UNDEFINED\x10\x00\x12\x0f\n\x0bH264_DECODE\x10\x01\x12\x0f\n\x0bH264_ENCODE\x10\x02\x12\x0e\n\nVP8_DECODE\x10\x03\x12\x0e\n\nVP8_ENCODE\x10\x04\x12\x0e\n\nVP9_DECODE\x10\x05\x12\x0e\n\nVP9_ENCODE\x10\x06\x12\x10\n\x0cVP9_2_DECODE\x10\x07\x12\x10\n\x0cVP9_2_ENCODE\x10\x08\x12\x0f\n\x0bH265_DECODE\x10\t\x12\x0f\n\x0bH265_ENCODE\x10\n\x12\x0f\n\x0bMJPG_DECODE\x10\x0b\x12\x0f\n\x0bMJPG_ENCODE\x10\x0c\"^\n\x0bGraphicsApi\x12\x1a\n\x16GRAPHICS_API_UNDEFINED\x10\x00\x12\x17\n\x13GRAPHICS_API_OPENGL\x10\x01\x12\x1a\n\x16GRAPHICS_API_OPENGL_ES\x10\x02\x42*Z(go.chromium.org/chromiumos/config/go/apib\x06proto3'
+  serialized_pb=b'\n#chromiumos/config/api/program.proto\x12\x15\x63hromiumos.config.api\x1a%chromiumos/config/api/component.proto\x1a\"chromiumos/config/api/design.proto\x1a%chromiumos/config/api/design_id.proto\x1a+chromiumos/config/api/device_brand_id.proto\x1a&chromiumos/config/api/program_id.proto\x1a$chromiumos/config/api/topology.proto\x1a=chromiumos/config/public_replication/public_replication.proto\":\n\x1c\x46irmwareConfigurationSegment\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04mask\x18\x02 \x01(\r\"k\n\x15\x44\x65signConfigIdSegment\x12\x32\n\tdesign_id\x18\x01 \x01(\x0b\x32\x1f.chromiumos.config.api.DesignId\x12\x0e\n\x06min_id\x18\x02 \x01(\r\x12\x0e\n\x06max_id\x18\x03 \x01(\r\"\xa2\x01\n\x12\x44\x65viceSignerConfig\x12\x38\n\x08\x62rand_id\x18\x01 \x01(\x0b\x32$.chromiumos.config.api.DeviceBrandIdH\x00\x12\x34\n\tdesign_id\x18\x03 \x01(\x0b\x32\x1f.chromiumos.config.api.DesignIdH\x00\x12\x0e\n\x06key_id\x18\x02 \x01(\tB\x0c\n\nidentifier\"\xfb\r\n\x07Program\x12S\n\x12public_replication\x18\x08 \x01(\x0b\x32\x37.chromiumos.config.public_replication.PublicReplication\x12,\n\x02id\x18\x01 \x01(\x0b\x32 .chromiumos.config.api.ProgramId\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x1b\n\x13mosys_platform_name\x18\n \x01(\t\x12\x39\n\x08platform\x18\x0b \x01(\x0b\x32\'.chromiumos.config.api.Program.Platform\x12@\n\x0c\x61udio_config\x18\x0c \x01(\x0b\x32*.chromiumos.config.api.Program.AudioConfig\x12R\n\x19\x64\x65sign_config_constraints\x18\x03 \x03(\x0b\x32/.chromiumos.config.api.Design.Config.Constraint\x12G\n\x0f\x63omponent_quals\x18\x04 \x03(\x0b\x32..chromiumos.config.api.Component.Qualification\x12\\\n\x1f\x66irmware_configuration_segments\x18\x05 \x03(\x0b\x32\x33.chromiumos.config.api.FirmwareConfigurationSegment\x12J\n\rssfc_segments\x18\t \x03(\x0b\x32\x33.chromiumos.config.api.FirmwareConfigurationSegment\x12O\n\x19\x64\x65sign_config_id_segments\x18\x07 \x03(\x0b\x32,.chromiumos.config.api.DesignConfigIdSegment\x12H\n\x15\x64\x65vice_signer_configs\x18\x06 \x03(\x0b\x32).chromiumos.config.api.DeviceSignerConfig\x1a\xcd\x06\n\x08Platform\x12\x12\n\nsoc_family\x18\x01 \x01(\t\x12>\n\x08soc_arch\x18\x02 \x01(\x0e\x32,.chromiumos.config.api.Program.Platform.Arch\x12\x12\n\ngpu_family\x18\x03 \x01(\t\x12J\n\rgraphics_apis\x18\x04 \x03(\x0e\x32\x33.chromiumos.config.api.Program.Platform.GraphicsApi\x12S\n\x0cvideo_codecs\x18\x05 \x03(\x0e\x32=.chromiumos.config.api.Program.Platform.AcceleratedVideoCodec\x12J\n\x0c\x63\x61pabilities\x18\x06 \x01(\x0b\x32\x34.chromiumos.config.api.Program.Platform.Capabilities\x1aP\n\x0c\x43\x61pabilities\x12\x17\n\x0fsuspend_to_idle\x18\x01 \x01(\x08\x12\x13\n\x0b\x64\x61rk_resume\x18\x02 \x01(\x08\x12\x12\n\nwake_on_dp\x18\x03 \x01(\x08\"A\n\x04\x41rch\x12\x10\n\x0c\x41RCH_UNKNOWN\x10\x00\x12\x07\n\x03X86\x10\x01\x12\n\n\x06X86_64\x10\x02\x12\x07\n\x03\x41RM\x10\x03\x12\t\n\x05\x41RM64\x10\x04\"\xf6\x01\n\x15\x41\x63\x63\x65leratedVideoCodec\x12\x13\n\x0f\x43ODEC_UNDEFINED\x10\x00\x12\x0f\n\x0bH264_DECODE\x10\x01\x12\x0f\n\x0bH264_ENCODE\x10\x02\x12\x0e\n\nVP8_DECODE\x10\x03\x12\x0e\n\nVP8_ENCODE\x10\x04\x12\x0e\n\nVP9_DECODE\x10\x05\x12\x0e\n\nVP9_ENCODE\x10\x06\x12\x10\n\x0cVP9_2_DECODE\x10\x07\x12\x10\n\x0cVP9_2_ENCODE\x10\x08\x12\x0f\n\x0bH265_DECODE\x10\t\x12\x0f\n\x0bH265_ENCODE\x10\n\x12\x0f\n\x0bMJPG_DECODE\x10\x0b\x12\x0f\n\x0bMJPG_ENCODE\x10\x0c\"^\n\x0bGraphicsApi\x12\x1a\n\x16GRAPHICS_API_UNDEFINED\x10\x00\x12\x17\n\x13GRAPHICS_API_OPENGL\x10\x01\x12\x1a\n\x16GRAPHICS_API_OPENGL_ES\x10\x02\x1a\x92\x01\n\x0b\x41udioConfig\x12N\n\x0c\x63\x61rd_configs\x18\x01 \x03(\x0b\x32\x38.chromiumos.config.api.HardwareFeatures.Audio.CardConfig\x12\x17\n\x0fhas_module_file\x18\x02 \x01(\x08\x12\x1a\n\x12\x64\x65\x66\x61ult_ucm_suffix\x18\x03 \x01(\tB*Z(go.chromium.org/chromiumos/config/go/apib\x06proto3'
   ,
-  dependencies=[chromiumos_dot_config_dot_api_dot_component__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_design__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_design__id__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_device__brand__id__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_program__id__pb2.DESCRIPTOR,chromiumos_dot_config_dot_public__replication_dot_public__replication__pb2.DESCRIPTOR,])
+  dependencies=[chromiumos_dot_config_dot_api_dot_component__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_design__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_design__id__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_device__brand__id__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_program__id__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_topology__pb2.DESCRIPTOR,chromiumos_dot_config_dot_public__replication_dot_public__replication__pb2.DESCRIPTOR,])
 
 
 
@@ -66,8 +67,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1663,
-  serialized_end=1728,
+  serialized_start=1925,
+  serialized_end=1990,
 )
 _sym_db.RegisterEnumDescriptor(_PROGRAM_PLATFORM_ARCH)
 
@@ -146,8 +147,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1731,
-  serialized_end=1977,
+  serialized_start=1993,
+  serialized_end=2239,
 )
 _sym_db.RegisterEnumDescriptor(_PROGRAM_PLATFORM_ACCELERATEDVIDEOCODEC)
 
@@ -176,8 +177,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1979,
-  serialized_end=2073,
+  serialized_start=2241,
+  serialized_end=2335,
 )
 _sym_db.RegisterEnumDescriptor(_PROGRAM_PLATFORM_GRAPHICSAPI)
 
@@ -216,8 +217,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=324,
-  serialized_end=382,
+  serialized_start=362,
+  serialized_end=420,
 )
 
 
@@ -262,8 +263,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=384,
-  serialized_end=491,
+  serialized_start=422,
+  serialized_end=529,
 )
 
 
@@ -313,11 +314,56 @@
       create_key=_descriptor._internal_create_key,
     fields=[]),
   ],
-  serialized_start=494,
-  serialized_end=656,
+  serialized_start=532,
+  serialized_end=694,
 )
 
 
+_PROGRAM_PLATFORM_CAPABILITIES = _descriptor.Descriptor(
+  name='Capabilities',
+  full_name='chromiumos.config.api.Program.Platform.Capabilities',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='suspend_to_idle', full_name='chromiumos.config.api.Program.Platform.Capabilities.suspend_to_idle', index=0,
+      number=1, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='dark_resume', full_name='chromiumos.config.api.Program.Platform.Capabilities.dark_resume', index=1,
+      number=2, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='wake_on_dp', full_name='chromiumos.config.api.Program.Platform.Capabilities.wake_on_dp', index=2,
+      number=3, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1843,
+  serialized_end=1923,
+)
+
 _PROGRAM_PLATFORM = _descriptor.Descriptor(
   name='Platform',
   full_name='chromiumos.config.api.Program.Platform',
@@ -361,10 +407,17 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='capabilities', full_name='chromiumos.config.api.Program.Platform.capabilities', index=5,
+      number=6, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
-  nested_types=[],
+  nested_types=[_PROGRAM_PLATFORM_CAPABILITIES, ],
   enum_types=[
     _PROGRAM_PLATFORM_ARCH,
     _PROGRAM_PLATFORM_ACCELERATEDVIDEOCODEC,
@@ -376,8 +429,53 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1386,
-  serialized_end=2073,
+  serialized_start=1490,
+  serialized_end=2335,
+)
+
+_PROGRAM_AUDIOCONFIG = _descriptor.Descriptor(
+  name='AudioConfig',
+  full_name='chromiumos.config.api.Program.AudioConfig',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='card_configs', full_name='chromiumos.config.api.Program.AudioConfig.card_configs', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='has_module_file', full_name='chromiumos.config.api.Program.AudioConfig.has_module_file', index=1,
+      number=2, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='default_ucm_suffix', full_name='chromiumos.config.api.Program.AudioConfig.default_ucm_suffix', index=2,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2338,
+  serialized_end=2484,
 )
 
 _PROGRAM = _descriptor.Descriptor(
@@ -424,42 +522,49 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='design_config_constraints', full_name='chromiumos.config.api.Program.design_config_constraints', index=5,
+      name='audio_config', full_name='chromiumos.config.api.Program.audio_config', index=5,
+      number=12, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='design_config_constraints', full_name='chromiumos.config.api.Program.design_config_constraints', index=6,
       number=3, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='component_quals', full_name='chromiumos.config.api.Program.component_quals', index=6,
+      name='component_quals', full_name='chromiumos.config.api.Program.component_quals', index=7,
       number=4, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='firmware_configuration_segments', full_name='chromiumos.config.api.Program.firmware_configuration_segments', index=7,
+      name='firmware_configuration_segments', full_name='chromiumos.config.api.Program.firmware_configuration_segments', index=8,
       number=5, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='ssfc_segments', full_name='chromiumos.config.api.Program.ssfc_segments', index=8,
+      name='ssfc_segments', full_name='chromiumos.config.api.Program.ssfc_segments', index=9,
       number=9, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='design_config_id_segments', full_name='chromiumos.config.api.Program.design_config_id_segments', index=9,
+      name='design_config_id_segments', full_name='chromiumos.config.api.Program.design_config_id_segments', index=10,
       number=7, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='device_signer_configs', full_name='chromiumos.config.api.Program.device_signer_configs', index=10,
+      name='device_signer_configs', full_name='chromiumos.config.api.Program.device_signer_configs', index=11,
       number=6, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
@@ -468,7 +573,7 @@
   ],
   extensions=[
   ],
-  nested_types=[_PROGRAM_PLATFORM, ],
+  nested_types=[_PROGRAM_PLATFORM, _PROGRAM_AUDIOCONFIG, ],
   enum_types=[
   ],
   serialized_options=None,
@@ -477,8 +582,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=659,
-  serialized_end=2073,
+  serialized_start=697,
+  serialized_end=2484,
 )
 
 _DESIGNCONFIGIDSEGMENT.fields_by_name['design_id'].message_type = chromiumos_dot_config_dot_api_dot_design__id__pb2._DESIGNID
@@ -490,16 +595,21 @@
 _DEVICESIGNERCONFIG.oneofs_by_name['identifier'].fields.append(
   _DEVICESIGNERCONFIG.fields_by_name['design_id'])
 _DEVICESIGNERCONFIG.fields_by_name['design_id'].containing_oneof = _DEVICESIGNERCONFIG.oneofs_by_name['identifier']
+_PROGRAM_PLATFORM_CAPABILITIES.containing_type = _PROGRAM_PLATFORM
 _PROGRAM_PLATFORM.fields_by_name['soc_arch'].enum_type = _PROGRAM_PLATFORM_ARCH
 _PROGRAM_PLATFORM.fields_by_name['graphics_apis'].enum_type = _PROGRAM_PLATFORM_GRAPHICSAPI
 _PROGRAM_PLATFORM.fields_by_name['video_codecs'].enum_type = _PROGRAM_PLATFORM_ACCELERATEDVIDEOCODEC
+_PROGRAM_PLATFORM.fields_by_name['capabilities'].message_type = _PROGRAM_PLATFORM_CAPABILITIES
 _PROGRAM_PLATFORM.containing_type = _PROGRAM
 _PROGRAM_PLATFORM_ARCH.containing_type = _PROGRAM_PLATFORM
 _PROGRAM_PLATFORM_ACCELERATEDVIDEOCODEC.containing_type = _PROGRAM_PLATFORM
 _PROGRAM_PLATFORM_GRAPHICSAPI.containing_type = _PROGRAM_PLATFORM
+_PROGRAM_AUDIOCONFIG.fields_by_name['card_configs'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._HARDWAREFEATURES_AUDIO_CARDCONFIG
+_PROGRAM_AUDIOCONFIG.containing_type = _PROGRAM
 _PROGRAM.fields_by_name['public_replication'].message_type = chromiumos_dot_config_dot_public__replication_dot_public__replication__pb2._PUBLICREPLICATION
 _PROGRAM.fields_by_name['id'].message_type = chromiumos_dot_config_dot_api_dot_program__id__pb2._PROGRAMID
 _PROGRAM.fields_by_name['platform'].message_type = _PROGRAM_PLATFORM
+_PROGRAM.fields_by_name['audio_config'].message_type = _PROGRAM_AUDIOCONFIG
 _PROGRAM.fields_by_name['design_config_constraints'].message_type = chromiumos_dot_config_dot_api_dot_design__pb2._DESIGN_CONFIG_CONSTRAINT
 _PROGRAM.fields_by_name['component_quals'].message_type = chromiumos_dot_config_dot_api_dot_component__pb2._COMPONENT_QUALIFICATION
 _PROGRAM.fields_by_name['firmware_configuration_segments'].message_type = _FIRMWARECONFIGURATIONSEGMENT
@@ -536,17 +646,33 @@
 Program = _reflection.GeneratedProtocolMessageType('Program', (_message.Message,), {
 
   'Platform' : _reflection.GeneratedProtocolMessageType('Platform', (_message.Message,), {
+
+    'Capabilities' : _reflection.GeneratedProtocolMessageType('Capabilities', (_message.Message,), {
+      'DESCRIPTOR' : _PROGRAM_PLATFORM_CAPABILITIES,
+      '__module__' : 'chromiumos.config.api.program_pb2'
+      # @@protoc_insertion_point(class_scope:chromiumos.config.api.Program.Platform.Capabilities)
+      })
+    ,
     'DESCRIPTOR' : _PROGRAM_PLATFORM,
     '__module__' : 'chromiumos.config.api.program_pb2'
     # @@protoc_insertion_point(class_scope:chromiumos.config.api.Program.Platform)
     })
   ,
+
+  'AudioConfig' : _reflection.GeneratedProtocolMessageType('AudioConfig', (_message.Message,), {
+    'DESCRIPTOR' : _PROGRAM_AUDIOCONFIG,
+    '__module__' : 'chromiumos.config.api.program_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.config.api.Program.AudioConfig)
+    })
+  ,
   'DESCRIPTOR' : _PROGRAM,
   '__module__' : 'chromiumos.config.api.program_pb2'
   # @@protoc_insertion_point(class_scope:chromiumos.config.api.Program)
   })
 _sym_db.RegisterMessage(Program)
 _sym_db.RegisterMessage(Program.Platform)
+_sym_db.RegisterMessage(Program.Platform.Capabilities)
+_sym_db.RegisterMessage(Program.AudioConfig)
 
 
 DESCRIPTOR._options = None
diff --git a/api/gen/chromiumos/config/api/software/health_config_pb2.py b/api/gen/chromiumos/config/api/software/health_config_pb2.py
new file mode 100644
index 0000000..c6ba31e
--- /dev/null
+++ b/api/gen/chromiumos/config/api/software/health_config_pb2.py
@@ -0,0 +1,160 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: chromiumos/config/api/software/health_config.proto
+"""Generated protocol buffer code."""
+from chromite.third_party.google.protobuf import descriptor as _descriptor
+from chromite.third_party.google.protobuf import message as _message
+from chromite.third_party.google.protobuf import reflection as _reflection
+from chromite.third_party.google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='chromiumos/config/api/software/health_config.proto',
+  package='chromiumos.config.api.software',
+  syntax='proto3',
+  serialized_options=b'Z1go.chromium.org/chromiumos/config/go/api/software',
+  create_key=_descriptor._internal_create_key,
+  serialized_pb=b'\n2chromiumos/config/api/software/health_config.proto\x12\x1e\x63hromiumos.config.api.software\"\xf1\x01\n\x0cHealthConfig\x12\x45\n\x07\x62\x61ttery\x18\x01 \x01(\x0b\x32\x34.chromiumos.config.api.software.HealthConfig.Battery\x12J\n\ncached_vpd\x18\x02 \x01(\x0b\x32\x36.chromiumos.config.api.software.HealthConfig.CachedVpd\x1a)\n\x07\x42\x61ttery\x12\x1e\n\x16has_smart_battery_info\x18\x01 \x01(\x08\x1a#\n\tCachedVpd\x12\x16\n\x0ehas_sku_number\x18\x01 \x01(\x08\x42\x33Z1go.chromium.org/chromiumos/config/go/api/softwareb\x06proto3'
+)
+
+
+
+
+_HEALTHCONFIG_BATTERY = _descriptor.Descriptor(
+  name='Battery',
+  full_name='chromiumos.config.api.software.HealthConfig.Battery',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='has_smart_battery_info', full_name='chromiumos.config.api.software.HealthConfig.Battery.has_smart_battery_info', index=0,
+      number=1, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=250,
+  serialized_end=291,
+)
+
+_HEALTHCONFIG_CACHEDVPD = _descriptor.Descriptor(
+  name='CachedVpd',
+  full_name='chromiumos.config.api.software.HealthConfig.CachedVpd',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='has_sku_number', full_name='chromiumos.config.api.software.HealthConfig.CachedVpd.has_sku_number', index=0,
+      number=1, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=293,
+  serialized_end=328,
+)
+
+_HEALTHCONFIG = _descriptor.Descriptor(
+  name='HealthConfig',
+  full_name='chromiumos.config.api.software.HealthConfig',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='battery', full_name='chromiumos.config.api.software.HealthConfig.battery', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='cached_vpd', full_name='chromiumos.config.api.software.HealthConfig.cached_vpd', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[_HEALTHCONFIG_BATTERY, _HEALTHCONFIG_CACHEDVPD, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=87,
+  serialized_end=328,
+)
+
+_HEALTHCONFIG_BATTERY.containing_type = _HEALTHCONFIG
+_HEALTHCONFIG_CACHEDVPD.containing_type = _HEALTHCONFIG
+_HEALTHCONFIG.fields_by_name['battery'].message_type = _HEALTHCONFIG_BATTERY
+_HEALTHCONFIG.fields_by_name['cached_vpd'].message_type = _HEALTHCONFIG_CACHEDVPD
+DESCRIPTOR.message_types_by_name['HealthConfig'] = _HEALTHCONFIG
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+HealthConfig = _reflection.GeneratedProtocolMessageType('HealthConfig', (_message.Message,), {
+
+  'Battery' : _reflection.GeneratedProtocolMessageType('Battery', (_message.Message,), {
+    'DESCRIPTOR' : _HEALTHCONFIG_BATTERY,
+    '__module__' : 'chromiumos.config.api.software.health_config_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.config.api.software.HealthConfig.Battery)
+    })
+  ,
+
+  'CachedVpd' : _reflection.GeneratedProtocolMessageType('CachedVpd', (_message.Message,), {
+    'DESCRIPTOR' : _HEALTHCONFIG_CACHEDVPD,
+    '__module__' : 'chromiumos.config.api.software.health_config_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.config.api.software.HealthConfig.CachedVpd)
+    })
+  ,
+  'DESCRIPTOR' : _HEALTHCONFIG,
+  '__module__' : 'chromiumos.config.api.software.health_config_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.config.api.software.HealthConfig)
+  })
+_sym_db.RegisterMessage(HealthConfig)
+_sym_db.RegisterMessage(HealthConfig.Battery)
+_sym_db.RegisterMessage(HealthConfig.CachedVpd)
+
+
+DESCRIPTOR._options = None
+# @@protoc_insertion_point(module_scope)
diff --git a/api/gen/chromiumos/config/api/software/software_config_pb2.py b/api/gen/chromiumos/config/api/software/software_config_pb2.py
index 48ee2c3..bfe01c3 100644
--- a/api/gen/chromiumos/config/api/software/software_config_pb2.py
+++ b/api/gen/chromiumos/config/api/software/software_config_pb2.py
@@ -17,9 +17,10 @@
 from chromite.api.gen.chromiumos.config.api import design_config_id_pb2 as chromiumos_dot_config_dot_api_dot_design__config__id__pb2
 from chromite.api.gen.chromiumos.config.api.software import audio_config_pb2 as chromiumos_dot_config_dot_api_dot_software_dot_audio__config__pb2
 from chromite.api.gen.chromiumos.config.api.software import bluetooth_config_pb2 as chromiumos_dot_config_dot_api_dot_software_dot_bluetooth__config__pb2
+from chromite.api.gen.chromiumos.config.api.software import camera_config_pb2 as chromiumos_dot_config_dot_api_dot_software_dot_camera__config__pb2
+from chromite.api.gen.chromiumos.config.api.software import health_config_pb2 as chromiumos_dot_config_dot_api_dot_software_dot_health__config__pb2
 from chromite.api.gen.chromiumos.config.api.software import power_config_pb2 as chromiumos_dot_config_dot_api_dot_software_dot_power__config__pb2
 from chromite.api.gen.chromiumos.config.api.software import wifi_config_pb2 as chromiumos_dot_config_dot_api_dot_software_dot_wifi__config__pb2
-from chromite.api.gen.chromiumos.config.api.software import camera_config_pb2 as chromiumos_dot_config_dot_api_dot_software_dot_camera__config__pb2
 from chromite.api.gen.chromiumos.config.api.software import ui_config_pb2 as chromiumos_dot_config_dot_api_dot_software_dot_ui__config__pb2
 from chromite.api.gen.chromiumos.config.public_replication import public_replication_pb2 as chromiumos_dot_config_dot_public__replication_dot_public__replication__pb2
 
@@ -30,9 +31,9 @@
   syntax='proto3',
   serialized_options=b'Z1go.chromium.org/chromiumos/config/go/api/software',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n4chromiumos/config/api/software/software_config.proto\x12\x1e\x63hromiumos.config.api.software\x1a\"chromiumos/build/api/factory.proto\x1a*chromiumos/build/api/firmware_config.proto\x1a\'chromiumos/build/api/system_image.proto\x1a,chromiumos/config/api/design_config_id.proto\x1a\x31\x63hromiumos/config/api/software/audio_config.proto\x1a\x35\x63hromiumos/config/api/software/bluetooth_config.proto\x1a\x31\x63hromiumos/config/api/software/power_config.proto\x1a\x30\x63hromiumos/config/api/software/wifi_config.proto\x1a\x32\x63hromiumos/config/api/software/camera_config.proto\x1a.chromiumos/config/api/software/ui_config.proto\x1a=chromiumos/config/public_replication/public_replication.proto\"\xfb\x07\n\x0eSoftwareConfig\x12S\n\x12public_replication\x18\x0c \x01(\x0b\x32\x37.chromiumos.config.public_replication.PublicReplication\x12?\n\x10\x64\x65sign_config_id\x18\x07 \x01(\x0b\x32%.chromiumos.config.api.DesignConfigId\x12H\n\x0eid_scan_config\x18\x08 \x01(\x0b\x32\x30.chromiumos.config.api.DesignConfigId.ScanConfig\x12\x36\n\x08\x66irmware\x18\x03 \x01(\x0b\x32$.chromiumos.build.api.FirmwareConfig\x12H\n\x15\x66irmware_build_config\x18\t \x01(\x0b\x32).chromiumos.build.api.FirmwareBuildConfig\x12K\n\x16\x66irmware_build_targets\x18\x10 \x01(\x0b\x32+.chromiumos.build.api.Firmware.BuildTargets\x12J\n\x13system_build_target\x18\r \x01(\x0b\x32-.chromiumos.build.api.SystemImage.BuildTarget\x12G\n\x14\x66\x61\x63tory_build_target\x18\x0e \x01(\x0b\x32).chromiumos.build.api.Factory.BuildTarget\x12I\n\x10\x62luetooth_config\x18\x04 \x01(\x0b\x32/.chromiumos.config.api.software.BluetoothConfig\x12\x41\n\x0cpower_config\x18\x05 \x01(\x0b\x32+.chromiumos.config.api.software.PowerConfig\x12\x42\n\raudio_configs\x18\n \x03(\x0b\x32+.chromiumos.config.api.software.AudioConfig\x12?\n\x0bwifi_config\x18\x0b \x01(\x0b\x32*.chromiumos.config.api.software.WifiConfig\x12\x43\n\rcamera_config\x18\x0f \x01(\x0b\x32,.chromiumos.config.api.software.CameraConfig\x12;\n\tui_config\x18\x11 \x01(\x0b\x32(.chromiumos.config.api.software.UiConfigJ\x04\x08\x01\x10\x02J\x04\x08\x02\x10\x03J\x04\x08\x06\x10\x07\x42\x33Z1go.chromium.org/chromiumos/config/go/api/softwareb\x06proto3'
+  serialized_pb=b'\n4chromiumos/config/api/software/software_config.proto\x12\x1e\x63hromiumos.config.api.software\x1a\"chromiumos/build/api/factory.proto\x1a*chromiumos/build/api/firmware_config.proto\x1a\'chromiumos/build/api/system_image.proto\x1a,chromiumos/config/api/design_config_id.proto\x1a\x31\x63hromiumos/config/api/software/audio_config.proto\x1a\x35\x63hromiumos/config/api/software/bluetooth_config.proto\x1a\x32\x63hromiumos/config/api/software/camera_config.proto\x1a\x32\x63hromiumos/config/api/software/health_config.proto\x1a\x31\x63hromiumos/config/api/software/power_config.proto\x1a\x30\x63hromiumos/config/api/software/wifi_config.proto\x1a.chromiumos/config/api/software/ui_config.proto\x1a=chromiumos/config/public_replication/public_replication.proto\"\xc0\x08\n\x0eSoftwareConfig\x12S\n\x12public_replication\x18\x0c \x01(\x0b\x32\x37.chromiumos.config.public_replication.PublicReplication\x12?\n\x10\x64\x65sign_config_id\x18\x07 \x01(\x0b\x32%.chromiumos.config.api.DesignConfigId\x12H\n\x0eid_scan_config\x18\x08 \x01(\x0b\x32\x30.chromiumos.config.api.DesignConfigId.ScanConfig\x12\x36\n\x08\x66irmware\x18\x03 \x01(\x0b\x32$.chromiumos.build.api.FirmwareConfig\x12H\n\x15\x66irmware_build_config\x18\t \x01(\x0b\x32).chromiumos.build.api.FirmwareBuildConfig\x12K\n\x16\x66irmware_build_targets\x18\x10 \x01(\x0b\x32+.chromiumos.build.api.Firmware.BuildTargets\x12J\n\x13system_build_target\x18\r \x01(\x0b\x32-.chromiumos.build.api.SystemImage.BuildTarget\x12G\n\x14\x66\x61\x63tory_build_target\x18\x0e \x01(\x0b\x32).chromiumos.build.api.Factory.BuildTarget\x12I\n\x10\x62luetooth_config\x18\x04 \x01(\x0b\x32/.chromiumos.config.api.software.BluetoothConfig\x12\x41\n\x0cpower_config\x18\x05 \x01(\x0b\x32+.chromiumos.config.api.software.PowerConfig\x12\x42\n\raudio_configs\x18\n \x03(\x0b\x32+.chromiumos.config.api.software.AudioConfig\x12?\n\x0bwifi_config\x18\x0b \x01(\x0b\x32*.chromiumos.config.api.software.WifiConfig\x12\x43\n\rhealth_config\x18\x12 \x01(\x0b\x32,.chromiumos.config.api.software.HealthConfig\x12\x43\n\rcamera_config\x18\x0f \x01(\x0b\x32,.chromiumos.config.api.software.CameraConfig\x12;\n\tui_config\x18\x11 \x01(\x0b\x32(.chromiumos.config.api.software.UiConfigJ\x04\x08\x01\x10\x02J\x04\x08\x02\x10\x03J\x04\x08\x06\x10\x07\x42\x33Z1go.chromium.org/chromiumos/config/go/api/softwareb\x06proto3'
   ,
-  dependencies=[chromiumos_dot_build_dot_api_dot_factory__pb2.DESCRIPTOR,chromiumos_dot_build_dot_api_dot_firmware__config__pb2.DESCRIPTOR,chromiumos_dot_build_dot_api_dot_system__image__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_design__config__id__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_software_dot_audio__config__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_software_dot_bluetooth__config__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_software_dot_power__config__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_software_dot_wifi__config__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_software_dot_camera__config__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_software_dot_ui__config__pb2.DESCRIPTOR,chromiumos_dot_config_dot_public__replication_dot_public__replication__pb2.DESCRIPTOR,])
+  dependencies=[chromiumos_dot_build_dot_api_dot_factory__pb2.DESCRIPTOR,chromiumos_dot_build_dot_api_dot_firmware__config__pb2.DESCRIPTOR,chromiumos_dot_build_dot_api_dot_system__image__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_design__config__id__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_software_dot_audio__config__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_software_dot_bluetooth__config__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_software_dot_camera__config__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_software_dot_health__config__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_software_dot_power__config__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_software_dot_wifi__config__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_software_dot_ui__config__pb2.DESCRIPTOR,chromiumos_dot_config_dot_public__replication_dot_public__replication__pb2.DESCRIPTOR,])
 
 
 
@@ -130,14 +131,21 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='camera_config', full_name='chromiumos.config.api.software.SoftwareConfig.camera_config', index=12,
+      name='health_config', full_name='chromiumos.config.api.software.SoftwareConfig.health_config', index=12,
+      number=18, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='camera_config', full_name='chromiumos.config.api.software.SoftwareConfig.camera_config', index=13,
       number=15, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='ui_config', full_name='chromiumos.config.api.software.SoftwareConfig.ui_config', index=13,
+      name='ui_config', full_name='chromiumos.config.api.software.SoftwareConfig.ui_config', index=14,
       number=17, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
@@ -155,8 +163,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=626,
-  serialized_end=1645,
+  serialized_start=678,
+  serialized_end=1766,
 )
 
 _SOFTWARECONFIG.fields_by_name['public_replication'].message_type = chromiumos_dot_config_dot_public__replication_dot_public__replication__pb2._PUBLICREPLICATION
@@ -171,6 +179,7 @@
 _SOFTWARECONFIG.fields_by_name['power_config'].message_type = chromiumos_dot_config_dot_api_dot_software_dot_power__config__pb2._POWERCONFIG
 _SOFTWARECONFIG.fields_by_name['audio_configs'].message_type = chromiumos_dot_config_dot_api_dot_software_dot_audio__config__pb2._AUDIOCONFIG
 _SOFTWARECONFIG.fields_by_name['wifi_config'].message_type = chromiumos_dot_config_dot_api_dot_software_dot_wifi__config__pb2._WIFICONFIG
+_SOFTWARECONFIG.fields_by_name['health_config'].message_type = chromiumos_dot_config_dot_api_dot_software_dot_health__config__pb2._HEALTHCONFIG
 _SOFTWARECONFIG.fields_by_name['camera_config'].message_type = chromiumos_dot_config_dot_api_dot_software_dot_camera__config__pb2._CAMERACONFIG
 _SOFTWARECONFIG.fields_by_name['ui_config'].message_type = chromiumos_dot_config_dot_api_dot_software_dot_ui__config__pb2._UICONFIG
 DESCRIPTOR.message_types_by_name['SoftwareConfig'] = _SOFTWARECONFIG
diff --git a/api/gen/chromiumos/config/api/software/wifi_config_pb2.py b/api/gen/chromiumos/config/api/software/wifi_config_pb2.py
index fbc8a51..b969d56 100644
--- a/api/gen/chromiumos/config/api/software/wifi_config_pb2.py
+++ b/api/gen/chromiumos/config/api/software/wifi_config_pb2.py
@@ -19,7 +19,7 @@
   syntax='proto3',
   serialized_options=b'Z1go.chromium.org/chromiumos/config/go/api/software',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n0chromiumos/config/api/software/wifi_config.proto\x12\x1e\x63hromiumos.config.api.software\"\xc7$\n\nWifiConfig\x12P\n\rath10k_config\x18\x01 \x01(\x0b\x32\x37.chromiumos.config.api.software.WifiConfig.Ath10kConfigH\x00\x12N\n\x0crtw88_config\x18\x02 \x01(\x0b\x32\x36.chromiumos.config.api.software.WifiConfig.Rtw88ConfigH\x00\x12N\n\x0cintel_config\x18\x03 \x01(\x0b\x32\x36.chromiumos.config.api.software.WifiConfig.IntelConfigH\x00\x1a\xa6\x02\n\x0c\x41th10kConfig\x12k\n\x17tablet_mode_power_table\x18\x01 \x01(\x0b\x32J.chromiumos.config.api.software.WifiConfig.Ath10kConfig.TransmitPowerChain\x12o\n\x1bnon_tablet_mode_power_table\x18\x02 \x01(\x0b\x32J.chromiumos.config.api.software.WifiConfig.Ath10kConfig.TransmitPowerChain\x1a\x38\n\x12TransmitPowerChain\x12\x10\n\x08limit_2g\x18\x01 \x01(\r\x12\x10\n\x08limit_5g\x18\x02 \x01(\r\x1a\x87\x05\n\x0bRtw88Config\x12j\n\x17tablet_mode_power_table\x18\x01 \x01(\x0b\x32I.chromiumos.config.api.software.WifiConfig.Rtw88Config.TransmitPowerChain\x12n\n\x1bnon_tablet_mode_power_table\x18\x02 \x01(\x0b\x32I.chromiumos.config.api.software.WifiConfig.Rtw88Config.TransmitPowerChain\x12U\n\noffset_fcc\x18\x03 \x01(\x0b\x32\x41.chromiumos.config.api.software.WifiConfig.Rtw88Config.GeoOffsets\x12T\n\toffset_eu\x18\x04 \x01(\x0b\x32\x41.chromiumos.config.api.software.WifiConfig.Rtw88Config.GeoOffsets\x12W\n\x0coffset_other\x18\x05 \x01(\x0b\x32\x41.chromiumos.config.api.software.WifiConfig.Rtw88Config.GeoOffsets\x1a\x62\n\x12TransmitPowerChain\x12\x10\n\x08limit_2g\x18\x01 \x01(\r\x12\x12\n\nlimit_5g_1\x18\x02 \x01(\r\x12\x12\n\nlimit_5g_3\x18\x03 \x01(\r\x12\x12\n\nlimit_5g_4\x18\x04 \x01(\r\x1a\x32\n\nGeoOffsets\x12\x11\n\toffset_2g\x18\x01 \x01(\r\x12\x11\n\toffset_5g\x18\x02 \x01(\r\x1a\x84\x1b\n\x0bIntelConfig\x12R\n\tsar_table\x18\x01 \x01(\x0b\x32?.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable\x12R\n\nwgds_table\x18\x02 \x01(\x0b\x32>.chromiumos.config.api.software.WifiConfig.IntelConfig.Offsets\x12O\n\tant_table\x18\x03 \x01(\x0b\x32<.chromiumos.config.api.software.WifiConfig.IntelConfig.Gains\x12R\n\nwtas_table\x18\x04 \x01(\x0b\x32>.chromiumos.config.api.software.WifiConfig.IntelConfig.Average\x12G\n\x03\x64sm\x18\x05 \x01(\x0b\x32:.chromiumos.config.api.software.WifiConfig.IntelConfig.DSM\x1a\xee\t\n\x08SarTable\x12\x19\n\x11sar_table_version\x18\x01 \x01(\r\x12u\n\x19tablet_mode_power_table_a\x18\x03 \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x12u\n\x19tablet_mode_power_table_b\x18\x04 \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x12y\n\x1dnon_tablet_mode_power_table_a\x18\x05 \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x12y\n\x1dnon_tablet_mode_power_table_b\x18\x06 \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x12y\n\x1d\x63\x64\x62_tablet_mode_power_table_a\x18\x07 \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x12y\n\x1d\x63\x64\x62_tablet_mode_power_table_b\x18\x08 \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x12}\n!cdb_non_tablet_mode_power_table_a\x18\t \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x12}\n!cdb_non_tablet_mode_power_table_b\x18\n \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x1a\xee\x01\n\x12TransmitPowerChain\x12\x10\n\x08limit_2g\x18\x01 \x01(\r\x12\x12\n\nlimit_5g_1\x18\x02 \x01(\r\x12\x12\n\nlimit_5g_2\x18\x03 \x01(\r\x12\x12\n\nlimit_5g_3\x18\x04 \x01(\r\x12\x12\n\nlimit_5g_4\x18\x05 \x01(\r\x12\x12\n\nlimit_5g_5\x18\x06 \x01(\r\x12\x12\n\nlimit_6g_1\x18\x07 \x01(\r\x12\x12\n\nlimit_6g_2\x18\x08 \x01(\r\x12\x12\n\nlimit_6g_3\x18\t \x01(\r\x12\x12\n\nlimit_6g_4\x18\n \x01(\r\x12\x12\n\nlimit_6g_5\x18\x0b \x01(\r\x1a\xfa\x03\n\x07Offsets\x12\x14\n\x0cwgds_version\x18\x01 \x01(\r\x12]\n\noffset_fcc\x18\x02 \x01(\x0b\x32I.chromiumos.config.api.software.WifiConfig.IntelConfig.Offsets.GeoOffsets\x12\\\n\toffset_eu\x18\x03 \x01(\x0b\x32I.chromiumos.config.api.software.WifiConfig.IntelConfig.Offsets.GeoOffsets\x12_\n\x0coffset_other\x18\x04 \x01(\x0b\x32I.chromiumos.config.api.software.WifiConfig.IntelConfig.Offsets.GeoOffsets\x1a\xba\x01\n\nGeoOffsets\x12\x0e\n\x06max_2g\x18\x01 \x01(\r\x12\x13\n\x0boffset_2g_a\x18\x02 \x01(\r\x12\x13\n\x0boffset_2g_b\x18\x03 \x01(\r\x12\x0e\n\x06max_5g\x18\x04 \x01(\r\x12\x13\n\x0boffset_5g_a\x18\x05 \x01(\r\x12\x13\n\x0boffset_5g_b\x18\x06 \x01(\r\x12\x0e\n\x06max_6g\x18\x07 \x01(\r\x12\x13\n\x0boffset_6g_a\x18\x08 \x01(\r\x12\x13\n\x0boffset_6g_b\x18\t \x01(\r\x1a\x8c\x04\n\x05Gains\x12\x19\n\x11\x61nt_table_version\x18\x01 \x01(\r\x12\x15\n\rant_mode_ppag\x18\x02 \x01(\r\x12\x62\n\x10\x61nt_gain_table_a\x18\x03 \x01(\x0b\x32H.chromiumos.config.api.software.WifiConfig.IntelConfig.Gains.AntennaGain\x12\x62\n\x10\x61nt_gain_table_b\x18\x04 \x01(\x0b\x32H.chromiumos.config.api.software.WifiConfig.IntelConfig.Gains.AntennaGain\x1a\x88\x02\n\x0b\x41ntennaGain\x12\x13\n\x0b\x61nt_gain_2g\x18\x01 \x01(\r\x12\x15\n\rant_gain_5g_1\x18\x02 \x01(\r\x12\x15\n\rant_gain_5g_2\x18\x03 \x01(\r\x12\x15\n\rant_gain_5g_3\x18\x04 \x01(\r\x12\x15\n\rant_gain_5g_4\x18\x05 \x01(\r\x12\x15\n\rant_gain_5g_5\x18\x06 \x01(\r\x12\x15\n\rant_gain_6g_1\x18\x07 \x01(\r\x12\x15\n\rant_gain_6g_2\x18\x08 \x01(\r\x12\x15\n\rant_gain_6g_3\x18\t \x01(\r\x12\x15\n\rant_gain_6g_4\x18\n \x01(\r\x12\x15\n\rant_gain_6g_5\x18\x0b \x01(\r\x1a\x87\x04\n\x07\x41verage\x12\x17\n\x0fsar_avg_version\x18\x01 \x01(\r\x12\x15\n\rtas_selection\x18\x02 \x01(\r\x12\x15\n\rtas_list_size\x18\x03 \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_1\x18\x04 \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_2\x18\x05 \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_3\x18\x06 \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_4\x18\x07 \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_5\x18\x08 \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_6\x18\t \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_7\x18\n \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_8\x18\x0b \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_9\x18\x0c \x01(\r\x12\x1a\n\x12\x64\x65ny_list_entry_10\x18\r \x01(\r\x12\x1a\n\x12\x64\x65ny_list_entry_11\x18\x0e \x01(\r\x12\x1a\n\x12\x64\x65ny_list_entry_12\x18\x0f \x01(\r\x12\x1a\n\x12\x64\x65ny_list_entry_13\x18\x10 \x01(\r\x12\x1a\n\x12\x64\x65ny_list_entry_14\x18\x11 \x01(\r\x12\x1a\n\x12\x64\x65ny_list_entry_15\x18\x12 \x01(\r\x12\x1a\n\x12\x64\x65ny_list_entry_16\x18\x13 \x01(\r\x1a\xd7\x01\n\x03\x44SM\x12#\n\x1b\x64isable_active_sdr_channels\x18\x02 \x01(\x03\x12!\n\x19support_indonesia_5g_band\x18\x03 \x01(\x03\x12\x1f\n\x17support_ultra_high_band\x18\x04 \x01(\x03\x12!\n\x19regulatory_configurations\x18\x05 \x01(\x03\x12\x1b\n\x13uart_configurations\x18\x06 \x01(\x03\x12\x17\n\x0f\x65nablement_11ax\x18\x07 \x01(\x03\x12\x0e\n\x06unii_4\x18\x08 \x01(\x03\x42\r\n\x0bwifi_configB3Z1go.chromium.org/chromiumos/config/go/api/softwareb\x06proto3'
+  serialized_pb=b'\n0chromiumos/config/api/software/wifi_config.proto\x12\x1e\x63hromiumos.config.api.software\"\x84+\n\nWifiConfig\x12P\n\rath10k_config\x18\x01 \x01(\x0b\x32\x37.chromiumos.config.api.software.WifiConfig.Ath10kConfigH\x00\x12N\n\x0crtw88_config\x18\x02 \x01(\x0b\x32\x36.chromiumos.config.api.software.WifiConfig.Rtw88ConfigH\x00\x12N\n\x0cintel_config\x18\x03 \x01(\x0b\x32\x36.chromiumos.config.api.software.WifiConfig.IntelConfigH\x00\x12J\n\nmtk_config\x18\x04 \x01(\x0b\x32\x34.chromiumos.config.api.software.WifiConfig.MtkConfigH\x00\x1a\xa6\x02\n\x0c\x41th10kConfig\x12k\n\x17tablet_mode_power_table\x18\x01 \x01(\x0b\x32J.chromiumos.config.api.software.WifiConfig.Ath10kConfig.TransmitPowerChain\x12o\n\x1bnon_tablet_mode_power_table\x18\x02 \x01(\x0b\x32J.chromiumos.config.api.software.WifiConfig.Ath10kConfig.TransmitPowerChain\x1a\x38\n\x12TransmitPowerChain\x12\x10\n\x08limit_2g\x18\x01 \x01(\r\x12\x10\n\x08limit_5g\x18\x02 \x01(\r\x1a\x87\x05\n\x0bRtw88Config\x12j\n\x17tablet_mode_power_table\x18\x01 \x01(\x0b\x32I.chromiumos.config.api.software.WifiConfig.Rtw88Config.TransmitPowerChain\x12n\n\x1bnon_tablet_mode_power_table\x18\x02 \x01(\x0b\x32I.chromiumos.config.api.software.WifiConfig.Rtw88Config.TransmitPowerChain\x12U\n\noffset_fcc\x18\x03 \x01(\x0b\x32\x41.chromiumos.config.api.software.WifiConfig.Rtw88Config.GeoOffsets\x12T\n\toffset_eu\x18\x04 \x01(\x0b\x32\x41.chromiumos.config.api.software.WifiConfig.Rtw88Config.GeoOffsets\x12W\n\x0coffset_other\x18\x05 \x01(\x0b\x32\x41.chromiumos.config.api.software.WifiConfig.Rtw88Config.GeoOffsets\x1a\x62\n\x12TransmitPowerChain\x12\x10\n\x08limit_2g\x18\x01 \x01(\r\x12\x12\n\nlimit_5g_1\x18\x02 \x01(\r\x12\x12\n\nlimit_5g_3\x18\x03 \x01(\r\x12\x12\n\nlimit_5g_4\x18\x04 \x01(\r\x1a\x32\n\nGeoOffsets\x12\x11\n\toffset_2g\x18\x01 \x01(\r\x12\x11\n\toffset_5g\x18\x02 \x01(\r\x1a\x84\x1b\n\x0bIntelConfig\x12R\n\tsar_table\x18\x01 \x01(\x0b\x32?.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable\x12R\n\nwgds_table\x18\x02 \x01(\x0b\x32>.chromiumos.config.api.software.WifiConfig.IntelConfig.Offsets\x12O\n\tant_table\x18\x03 \x01(\x0b\x32<.chromiumos.config.api.software.WifiConfig.IntelConfig.Gains\x12R\n\nwtas_table\x18\x04 \x01(\x0b\x32>.chromiumos.config.api.software.WifiConfig.IntelConfig.Average\x12G\n\x03\x64sm\x18\x05 \x01(\x0b\x32:.chromiumos.config.api.software.WifiConfig.IntelConfig.DSM\x1a\xee\t\n\x08SarTable\x12\x19\n\x11sar_table_version\x18\x01 \x01(\r\x12u\n\x19tablet_mode_power_table_a\x18\x03 \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x12u\n\x19tablet_mode_power_table_b\x18\x04 \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x12y\n\x1dnon_tablet_mode_power_table_a\x18\x05 \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x12y\n\x1dnon_tablet_mode_power_table_b\x18\x06 \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x12y\n\x1d\x63\x64\x62_tablet_mode_power_table_a\x18\x07 \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x12y\n\x1d\x63\x64\x62_tablet_mode_power_table_b\x18\x08 \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x12}\n!cdb_non_tablet_mode_power_table_a\x18\t \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x12}\n!cdb_non_tablet_mode_power_table_b\x18\n \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x1a\xee\x01\n\x12TransmitPowerChain\x12\x10\n\x08limit_2g\x18\x01 \x01(\r\x12\x12\n\nlimit_5g_1\x18\x02 \x01(\r\x12\x12\n\nlimit_5g_2\x18\x03 \x01(\r\x12\x12\n\nlimit_5g_3\x18\x04 \x01(\r\x12\x12\n\nlimit_5g_4\x18\x05 \x01(\r\x12\x12\n\nlimit_5g_5\x18\x06 \x01(\r\x12\x12\n\nlimit_6g_1\x18\x07 \x01(\r\x12\x12\n\nlimit_6g_2\x18\x08 \x01(\r\x12\x12\n\nlimit_6g_3\x18\t \x01(\r\x12\x12\n\nlimit_6g_4\x18\n \x01(\r\x12\x12\n\nlimit_6g_5\x18\x0b \x01(\r\x1a\xfa\x03\n\x07Offsets\x12\x14\n\x0cwgds_version\x18\x01 \x01(\r\x12]\n\noffset_fcc\x18\x02 \x01(\x0b\x32I.chromiumos.config.api.software.WifiConfig.IntelConfig.Offsets.GeoOffsets\x12\\\n\toffset_eu\x18\x03 \x01(\x0b\x32I.chromiumos.config.api.software.WifiConfig.IntelConfig.Offsets.GeoOffsets\x12_\n\x0coffset_other\x18\x04 \x01(\x0b\x32I.chromiumos.config.api.software.WifiConfig.IntelConfig.Offsets.GeoOffsets\x1a\xba\x01\n\nGeoOffsets\x12\x0e\n\x06max_2g\x18\x01 \x01(\r\x12\x13\n\x0boffset_2g_a\x18\x02 \x01(\r\x12\x13\n\x0boffset_2g_b\x18\x03 \x01(\r\x12\x0e\n\x06max_5g\x18\x04 \x01(\r\x12\x13\n\x0boffset_5g_a\x18\x05 \x01(\r\x12\x13\n\x0boffset_5g_b\x18\x06 \x01(\r\x12\x0e\n\x06max_6g\x18\x07 \x01(\r\x12\x13\n\x0boffset_6g_a\x18\x08 \x01(\r\x12\x13\n\x0boffset_6g_b\x18\t \x01(\r\x1a\x8c\x04\n\x05Gains\x12\x19\n\x11\x61nt_table_version\x18\x01 \x01(\r\x12\x15\n\rant_mode_ppag\x18\x02 \x01(\r\x12\x62\n\x10\x61nt_gain_table_a\x18\x03 \x01(\x0b\x32H.chromiumos.config.api.software.WifiConfig.IntelConfig.Gains.AntennaGain\x12\x62\n\x10\x61nt_gain_table_b\x18\x04 \x01(\x0b\x32H.chromiumos.config.api.software.WifiConfig.IntelConfig.Gains.AntennaGain\x1a\x88\x02\n\x0b\x41ntennaGain\x12\x13\n\x0b\x61nt_gain_2g\x18\x01 \x01(\r\x12\x15\n\rant_gain_5g_1\x18\x02 \x01(\r\x12\x15\n\rant_gain_5g_2\x18\x03 \x01(\r\x12\x15\n\rant_gain_5g_3\x18\x04 \x01(\r\x12\x15\n\rant_gain_5g_4\x18\x05 \x01(\r\x12\x15\n\rant_gain_5g_5\x18\x06 \x01(\r\x12\x15\n\rant_gain_6g_1\x18\x07 \x01(\r\x12\x15\n\rant_gain_6g_2\x18\x08 \x01(\r\x12\x15\n\rant_gain_6g_3\x18\t \x01(\r\x12\x15\n\rant_gain_6g_4\x18\n \x01(\r\x12\x15\n\rant_gain_6g_5\x18\x0b \x01(\r\x1a\x87\x04\n\x07\x41verage\x12\x17\n\x0fsar_avg_version\x18\x01 \x01(\r\x12\x15\n\rtas_selection\x18\x02 \x01(\r\x12\x15\n\rtas_list_size\x18\x03 \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_1\x18\x04 \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_2\x18\x05 \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_3\x18\x06 \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_4\x18\x07 \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_5\x18\x08 \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_6\x18\t \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_7\x18\n \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_8\x18\x0b \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_9\x18\x0c \x01(\r\x12\x1a\n\x12\x64\x65ny_list_entry_10\x18\r \x01(\r\x12\x1a\n\x12\x64\x65ny_list_entry_11\x18\x0e \x01(\r\x12\x1a\n\x12\x64\x65ny_list_entry_12\x18\x0f \x01(\r\x12\x1a\n\x12\x64\x65ny_list_entry_13\x18\x10 \x01(\r\x12\x1a\n\x12\x64\x65ny_list_entry_14\x18\x11 \x01(\r\x12\x1a\n\x12\x64\x65ny_list_entry_15\x18\x12 \x01(\r\x12\x1a\n\x12\x64\x65ny_list_entry_16\x18\x13 \x01(\r\x1a\xd7\x01\n\x03\x44SM\x12#\n\x1b\x64isable_active_sdr_channels\x18\x02 \x01(\x03\x12!\n\x19support_indonesia_5g_band\x18\x03 \x01(\x03\x12\x1f\n\x17support_ultra_high_band\x18\x04 \x01(\x03\x12!\n\x19regulatory_configurations\x18\x05 \x01(\x03\x12\x1b\n\x13uart_configurations\x18\x06 \x01(\x03\x12\x17\n\x0f\x65nablement_11ax\x18\x07 \x01(\x03\x12\x0e\n\x06unii_4\x18\x08 \x01(\x03\x1a\xee\x05\n\tMtkConfig\x12h\n\x17tablet_mode_power_table\x18\x01 \x01(\x0b\x32G.chromiumos.config.api.software.WifiConfig.MtkConfig.TransmitPowerChain\x12l\n\x1bnon_tablet_mode_power_table\x18\x02 \x01(\x0b\x32G.chromiumos.config.api.software.WifiConfig.MtkConfig.TransmitPowerChain\x12\x63\n\x0f\x66\x63\x63_power_table\x18\x03 \x01(\x0b\x32J.chromiumos.config.api.software.WifiConfig.MtkConfig.GeoTransmitPowerChain\x12\x62\n\x0e\x65u_power_table\x18\x04 \x01(\x0b\x32J.chromiumos.config.api.software.WifiConfig.MtkConfig.GeoTransmitPowerChain\x12\x65\n\x11other_power_table\x18\x05 \x01(\x0b\x32J.chromiumos.config.api.software.WifiConfig.MtkConfig.GeoTransmitPowerChain\x1av\n\x12TransmitPowerChain\x12\x10\n\x08limit_2g\x18\x01 \x01(\r\x12\x12\n\nlimit_5g_1\x18\x02 \x01(\r\x12\x12\n\nlimit_5g_2\x18\x03 \x01(\r\x12\x12\n\nlimit_5g_3\x18\x04 \x01(\r\x12\x12\n\nlimit_5g_4\x18\x05 \x01(\r\x1a\x61\n\x15GeoTransmitPowerChain\x12\x10\n\x08limit_2g\x18\x01 \x01(\r\x12\x10\n\x08limit_5g\x18\x02 \x01(\r\x12\x11\n\toffset_2g\x18\x03 \x01(\r\x12\x11\n\toffset_5g\x18\x04 \x01(\rB\r\n\x0bwifi_configB3Z1go.chromium.org/chromiumos/config/go/api/softwareb\x06proto3'
 )
 
 
@@ -59,8 +59,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=580,
-  serialized_end=636,
+  serialized_start=656,
+  serialized_end=712,
 )
 
 _WIFICONFIG_ATH10KCONFIG = _descriptor.Descriptor(
@@ -97,8 +97,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=342,
-  serialized_end=636,
+  serialized_start=418,
+  serialized_end=712,
 )
 
 _WIFICONFIG_RTW88CONFIG_TRANSMITPOWERCHAIN = _descriptor.Descriptor(
@@ -149,8 +149,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1136,
-  serialized_end=1234,
+  serialized_start=1212,
+  serialized_end=1310,
 )
 
 _WIFICONFIG_RTW88CONFIG_GEOOFFSETS = _descriptor.Descriptor(
@@ -187,8 +187,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1236,
-  serialized_end=1286,
+  serialized_start=1312,
+  serialized_end=1362,
 )
 
 _WIFICONFIG_RTW88CONFIG = _descriptor.Descriptor(
@@ -246,8 +246,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=639,
-  serialized_end=1286,
+  serialized_start=715,
+  serialized_end=1362,
 )
 
 _WIFICONFIG_INTELCONFIG_SARTABLE_TRANSMITPOWERCHAIN = _descriptor.Descriptor(
@@ -347,8 +347,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2735,
-  serialized_end=2973,
+  serialized_start=2811,
+  serialized_end=3049,
 )
 
 _WIFICONFIG_INTELCONFIG_SARTABLE = _descriptor.Descriptor(
@@ -434,8 +434,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1711,
-  serialized_end=2973,
+  serialized_start=1787,
+  serialized_end=3049,
 )
 
 _WIFICONFIG_INTELCONFIG_OFFSETS_GEOOFFSETS = _descriptor.Descriptor(
@@ -521,8 +521,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3296,
-  serialized_end=3482,
+  serialized_start=3372,
+  serialized_end=3558,
 )
 
 _WIFICONFIG_INTELCONFIG_OFFSETS = _descriptor.Descriptor(
@@ -573,8 +573,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2976,
-  serialized_end=3482,
+  serialized_start=3052,
+  serialized_end=3558,
 )
 
 _WIFICONFIG_INTELCONFIG_GAINS_ANTENNAGAIN = _descriptor.Descriptor(
@@ -674,8 +674,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3745,
-  serialized_end=4009,
+  serialized_start=3821,
+  serialized_end=4085,
 )
 
 _WIFICONFIG_INTELCONFIG_GAINS = _descriptor.Descriptor(
@@ -726,8 +726,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3485,
-  serialized_end=4009,
+  serialized_start=3561,
+  serialized_end=4085,
 )
 
 _WIFICONFIG_INTELCONFIG_AVERAGE = _descriptor.Descriptor(
@@ -883,8 +883,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4012,
-  serialized_end=4531,
+  serialized_start=4088,
+  serialized_end=4607,
 )
 
 _WIFICONFIG_INTELCONFIG_DSM = _descriptor.Descriptor(
@@ -956,8 +956,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4534,
-  serialized_end=4749,
+  serialized_start=4610,
+  serialized_end=4825,
 )
 
 _WIFICONFIG_INTELCONFIG = _descriptor.Descriptor(
@@ -1015,8 +1015,178 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1289,
-  serialized_end=4749,
+  serialized_start=1365,
+  serialized_end=4825,
+)
+
+_WIFICONFIG_MTKCONFIG_TRANSMITPOWERCHAIN = _descriptor.Descriptor(
+  name='TransmitPowerChain',
+  full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.TransmitPowerChain',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='limit_2g', full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.TransmitPowerChain.limit_2g', index=0,
+      number=1, type=13, cpp_type=3, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='limit_5g_1', full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.TransmitPowerChain.limit_5g_1', index=1,
+      number=2, type=13, cpp_type=3, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='limit_5g_2', full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.TransmitPowerChain.limit_5g_2', index=2,
+      number=3, type=13, cpp_type=3, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='limit_5g_3', full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.TransmitPowerChain.limit_5g_3', index=3,
+      number=4, type=13, cpp_type=3, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='limit_5g_4', full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.TransmitPowerChain.limit_5g_4', index=4,
+      number=5, type=13, cpp_type=3, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2811,
+  serialized_end=2929,
+)
+
+_WIFICONFIG_MTKCONFIG_GEOTRANSMITPOWERCHAIN = _descriptor.Descriptor(
+  name='GeoTransmitPowerChain',
+  full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.GeoTransmitPowerChain',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='limit_2g', full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.GeoTransmitPowerChain.limit_2g', index=0,
+      number=1, type=13, cpp_type=3, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='limit_5g', full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.GeoTransmitPowerChain.limit_5g', index=1,
+      number=2, type=13, cpp_type=3, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='offset_2g', full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.GeoTransmitPowerChain.offset_2g', index=2,
+      number=3, type=13, cpp_type=3, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='offset_5g', full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.GeoTransmitPowerChain.offset_5g', index=3,
+      number=4, type=13, cpp_type=3, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=5481,
+  serialized_end=5578,
+)
+
+_WIFICONFIG_MTKCONFIG = _descriptor.Descriptor(
+  name='MtkConfig',
+  full_name='chromiumos.config.api.software.WifiConfig.MtkConfig',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='tablet_mode_power_table', full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.tablet_mode_power_table', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='non_tablet_mode_power_table', full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.non_tablet_mode_power_table', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='fcc_power_table', full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.fcc_power_table', index=2,
+      number=3, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='eu_power_table', full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.eu_power_table', index=3,
+      number=4, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='other_power_table', full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.other_power_table', index=4,
+      number=5, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[_WIFICONFIG_MTKCONFIG_TRANSMITPOWERCHAIN, _WIFICONFIG_MTKCONFIG_GEOTRANSMITPOWERCHAIN, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=4828,
+  serialized_end=5578,
 )
 
 _WIFICONFIG = _descriptor.Descriptor(
@@ -1048,10 +1218,17 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='mtk_config', full_name='chromiumos.config.api.software.WifiConfig.mtk_config', index=3,
+      number=4, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
-  nested_types=[_WIFICONFIG_ATH10KCONFIG, _WIFICONFIG_RTW88CONFIG, _WIFICONFIG_INTELCONFIG, ],
+  nested_types=[_WIFICONFIG_ATH10KCONFIG, _WIFICONFIG_RTW88CONFIG, _WIFICONFIG_INTELCONFIG, _WIFICONFIG_MTKCONFIG, ],
   enum_types=[
   ],
   serialized_options=None,
@@ -1066,7 +1243,7 @@
     fields=[]),
   ],
   serialized_start=85,
-  serialized_end=4764,
+  serialized_end=5593,
 )
 
 _WIFICONFIG_ATH10KCONFIG_TRANSMITPOWERCHAIN.containing_type = _WIFICONFIG_ATH10KCONFIG
@@ -1108,9 +1285,18 @@
 _WIFICONFIG_INTELCONFIG.fields_by_name['wtas_table'].message_type = _WIFICONFIG_INTELCONFIG_AVERAGE
 _WIFICONFIG_INTELCONFIG.fields_by_name['dsm'].message_type = _WIFICONFIG_INTELCONFIG_DSM
 _WIFICONFIG_INTELCONFIG.containing_type = _WIFICONFIG
+_WIFICONFIG_MTKCONFIG_TRANSMITPOWERCHAIN.containing_type = _WIFICONFIG_MTKCONFIG
+_WIFICONFIG_MTKCONFIG_GEOTRANSMITPOWERCHAIN.containing_type = _WIFICONFIG_MTKCONFIG
+_WIFICONFIG_MTKCONFIG.fields_by_name['tablet_mode_power_table'].message_type = _WIFICONFIG_MTKCONFIG_TRANSMITPOWERCHAIN
+_WIFICONFIG_MTKCONFIG.fields_by_name['non_tablet_mode_power_table'].message_type = _WIFICONFIG_MTKCONFIG_TRANSMITPOWERCHAIN
+_WIFICONFIG_MTKCONFIG.fields_by_name['fcc_power_table'].message_type = _WIFICONFIG_MTKCONFIG_GEOTRANSMITPOWERCHAIN
+_WIFICONFIG_MTKCONFIG.fields_by_name['eu_power_table'].message_type = _WIFICONFIG_MTKCONFIG_GEOTRANSMITPOWERCHAIN
+_WIFICONFIG_MTKCONFIG.fields_by_name['other_power_table'].message_type = _WIFICONFIG_MTKCONFIG_GEOTRANSMITPOWERCHAIN
+_WIFICONFIG_MTKCONFIG.containing_type = _WIFICONFIG
 _WIFICONFIG.fields_by_name['ath10k_config'].message_type = _WIFICONFIG_ATH10KCONFIG
 _WIFICONFIG.fields_by_name['rtw88_config'].message_type = _WIFICONFIG_RTW88CONFIG
 _WIFICONFIG.fields_by_name['intel_config'].message_type = _WIFICONFIG_INTELCONFIG
+_WIFICONFIG.fields_by_name['mtk_config'].message_type = _WIFICONFIG_MTKCONFIG
 _WIFICONFIG.oneofs_by_name['wifi_config'].fields.append(
   _WIFICONFIG.fields_by_name['ath10k_config'])
 _WIFICONFIG.fields_by_name['ath10k_config'].containing_oneof = _WIFICONFIG.oneofs_by_name['wifi_config']
@@ -1120,6 +1306,9 @@
 _WIFICONFIG.oneofs_by_name['wifi_config'].fields.append(
   _WIFICONFIG.fields_by_name['intel_config'])
 _WIFICONFIG.fields_by_name['intel_config'].containing_oneof = _WIFICONFIG.oneofs_by_name['wifi_config']
+_WIFICONFIG.oneofs_by_name['wifi_config'].fields.append(
+  _WIFICONFIG.fields_by_name['mtk_config'])
+_WIFICONFIG.fields_by_name['mtk_config'].containing_oneof = _WIFICONFIG.oneofs_by_name['wifi_config']
 DESCRIPTOR.message_types_by_name['WifiConfig'] = _WIFICONFIG
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
@@ -1222,6 +1411,27 @@
     # @@protoc_insertion_point(class_scope:chromiumos.config.api.software.WifiConfig.IntelConfig)
     })
   ,
+
+  'MtkConfig' : _reflection.GeneratedProtocolMessageType('MtkConfig', (_message.Message,), {
+
+    'TransmitPowerChain' : _reflection.GeneratedProtocolMessageType('TransmitPowerChain', (_message.Message,), {
+      'DESCRIPTOR' : _WIFICONFIG_MTKCONFIG_TRANSMITPOWERCHAIN,
+      '__module__' : 'chromiumos.config.api.software.wifi_config_pb2'
+      # @@protoc_insertion_point(class_scope:chromiumos.config.api.software.WifiConfig.MtkConfig.TransmitPowerChain)
+      })
+    ,
+
+    'GeoTransmitPowerChain' : _reflection.GeneratedProtocolMessageType('GeoTransmitPowerChain', (_message.Message,), {
+      'DESCRIPTOR' : _WIFICONFIG_MTKCONFIG_GEOTRANSMITPOWERCHAIN,
+      '__module__' : 'chromiumos.config.api.software.wifi_config_pb2'
+      # @@protoc_insertion_point(class_scope:chromiumos.config.api.software.WifiConfig.MtkConfig.GeoTransmitPowerChain)
+      })
+    ,
+    'DESCRIPTOR' : _WIFICONFIG_MTKCONFIG,
+    '__module__' : 'chromiumos.config.api.software.wifi_config_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.config.api.software.WifiConfig.MtkConfig)
+    })
+  ,
   'DESCRIPTOR' : _WIFICONFIG,
   '__module__' : 'chromiumos.config.api.software.wifi_config_pb2'
   # @@protoc_insertion_point(class_scope:chromiumos.config.api.software.WifiConfig)
@@ -1241,6 +1451,9 @@
 _sym_db.RegisterMessage(WifiConfig.IntelConfig.Gains.AntennaGain)
 _sym_db.RegisterMessage(WifiConfig.IntelConfig.Average)
 _sym_db.RegisterMessage(WifiConfig.IntelConfig.DSM)
+_sym_db.RegisterMessage(WifiConfig.MtkConfig)
+_sym_db.RegisterMessage(WifiConfig.MtkConfig.TransmitPowerChain)
+_sym_db.RegisterMessage(WifiConfig.MtkConfig.GeoTransmitPowerChain)
 
 
 DESCRIPTOR._options = None
diff --git a/api/gen/chromiumos/config/api/topology_pb2.py b/api/gen/chromiumos/config/api/topology_pb2.py
index 060280a..c3afc21 100644
--- a/api/gen/chromiumos/config/api/topology_pb2.py
+++ b/api/gen/chromiumos/config/api/topology_pb2.py
@@ -12,6 +12,7 @@
 
 
 from chromite.api.gen.chromiumos.config.api import component_pb2 as chromiumos_dot_config_dot_api_dot_component__pb2
+from chromite.third_party.google.protobuf import wrappers_pb2 as google_dot_protobuf_dot_wrappers__pb2
 
 
 DESCRIPTOR = _descriptor.FileDescriptor(
@@ -20,9 +21,9 @@
   syntax='proto3',
   serialized_options=b'Z(go.chromium.org/chromiumos/config/go/api',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n$chromiumos/config/api/topology.proto\x12\x15\x63hromiumos.config.api\x1a%chromiumos/config/api/component.proto\"\xdf\x05\n\x08Topology\x12\n\n\x02id\x18\x01 \x01(\t\x12\x32\n\x04type\x18\x02 \x01(\x0e\x32$.chromiumos.config.api.Topology.Type\x12\x45\n\x0b\x64\x65scription\x18\x03 \x03(\x0b\x32\x30.chromiumos.config.api.Topology.DescriptionEntry\x12\x41\n\x10hardware_feature\x18\x04 \x01(\x0b\x32\'.chromiumos.config.api.HardwareFeatures\x1a\x32\n\x10\x44\x65scriptionEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xd4\x03\n\x04Type\x12\x10\n\x0cTYPE_UNKNOWN\x10\x00\x12\n\n\x06SCREEN\x10\x01\x12\x0f\n\x0b\x46ORM_FACTOR\x10\x02\x12\t\n\x05\x41UDIO\x10\x03\x12\n\n\x06STYLUS\x10\x04\x12\x0c\n\x08KEYBOARD\x10\x05\x12\x0b\n\x07THERMAL\x10\x06\x12\n\n\x06\x43\x41MERA\x10\x07\x12(\n$ACCELEROMETER_GYROSCOPE_MAGNETOMETER\x10\x08\x12\x0f\n\x0b\x46INGERPRINT\x10\t\x12\x14\n\x10PROXIMITY_SENSOR\x10\n\x12\x12\n\x0e\x44\x41UGHTER_BOARD\x10\x0b\x12\x18\n\x14NON_VOLATILE_STORAGE\x10\x0c\x12\x07\n\x03RAM\x10\r\x12\x08\n\x04WIFI\x10\x0e\x12\r\n\tLTE_BOARD\x10\x0f\x12\r\n\tSD_READER\x10\x10\x12\x13\n\x0fMOTHERBOARD_USB\x10\x11\x12\r\n\tBLUETOOTH\x10\x12\x12\x0e\n\nBARRELJACK\x10\x13\x12\x10\n\x0cPOWER_BUTTON\x10\x14\x12\x11\n\rVOLUME_BUTTON\x10\x15\x12\x06\n\x02\x45\x43\x10\x16\x12\t\n\x05TOUCH\x10\x17\x12\x07\n\x03TPM\x10\x18\x12\x1a\n\x16MICROPHONE_MUTE_SWITCH\x10\x19\x12\x0b\n\x07\x42\x41TTERY\x10\x1a\x12\x08\n\x04HDMI\x10\x1b\x12\x07\n\x03SOC\x10\x1c\"\xa8\x01\n\x08\x44uration\x12\x32\n\x04type\x18\x01 \x01(\x0e\x32$.chromiumos.config.api.Duration.Type\x12\r\n\x05value\x18\x02 \x01(\x05\"Y\n\x04Type\x12\x10\n\x0cTYPE_UNKNOWN\x10\x00\x12\x10\n\x0cMILLISECONDS\x10\x01\x12\x0b\n\x07SECONDS\x10\x02\x12\x0b\n\x07MINUTES\x10\x03\x12\t\n\x05HOURS\x10\x04\x12\x08\n\x04\x44\x41YS\x10\x05\"\xe2G\n\x10HardwareFeatures\x12;\n\x05usb_c\x18\x01 \x01(\x0b\x32,.chromiumos.config.api.HardwareFeatures.UsbC\x12;\n\x05usb_a\x18\x02 \x01(\x0b\x32,.chromiumos.config.api.HardwareFeatures.UsbA\x12\x38\n\x03lte\x18\x03 \x01(\x0b\x32+.chromiumos.config.api.HardwareFeatures.Lte\x12:\n\x04hdmi\x18\x04 \x01(\x0b\x32,.chromiumos.config.api.HardwareFeatures.Hdmi\x12P\n\tfw_config\x18\x05 \x01(\x0b\x32=.chromiumos.config.api.HardwareFeatures.FirmwareConfiguration\x12<\n\x05\x61udio\x18\x06 \x01(\x0b\x32-.chromiumos.config.api.HardwareFeatures.Audio\x12>\n\x06\x63\x61mera\x18\x07 \x01(\x0b\x32..chromiumos.config.api.HardwareFeatures.Camera\x12L\n\raccelerometer\x18\x08 \x01(\x0b\x32\x35.chromiumos.config.api.HardwareFeatures.Accelerometer\x12\x44\n\tgyroscope\x18\t \x01(\x0b\x32\x31.chromiumos.config.api.HardwareFeatures.Gyroscope\x12J\n\x0cmagnetometer\x18\n \x01(\x0b\x32\x34.chromiumos.config.api.HardwareFeatures.Magnetometer\x12I\n\x0clight_sensor\x18\x0b \x01(\x0b\x32\x33.chromiumos.config.api.HardwareFeatures.LightSensor\x12>\n\x06screen\x18\x0c \x01(\x0b\x32..chromiumos.config.api.HardwareFeatures.Screen\x12G\n\x0b\x66orm_factor\x18\r \x01(\x0b\x32\x32.chromiumos.config.api.HardwareFeatures.FormFactor\x12>\n\x06stylus\x18\x0e \x01(\x0b\x32..chromiumos.config.api.HardwareFeatures.Stylus\x12\x42\n\x08keyboard\x18\x0f \x01(\x0b\x32\x30.chromiumos.config.api.HardwareFeatures.Keyboard\x12>\n\x06memory\x18\x10 \x01(\x0b\x32..chromiumos.config.api.HardwareFeatures.Memory\x12H\n\x0b\x66ingerprint\x18\x11 \x01(\x0b\x32\x33.chromiumos.config.api.HardwareFeatures.Fingerprint\x12@\n\x07storage\x18\x12 \x01(\x0b\x32/.chromiumos.config.api.HardwareFeatures.Storage\x12\x44\n\tbluetooth\x18\x13 \x01(\x0b\x32\x31.chromiumos.config.api.HardwareFeatures.Bluetooth\x12\x46\n\nbarreljack\x18\x14 \x01(\x0b\x32\x32.chromiumos.config.api.HardwareFeatures.BarrelJack\x12:\n\x04wifi\x18\x17 \x01(\x0b\x32,.chromiumos.config.api.HardwareFeatures.Wifi\x12\x44\n\x0cpower_button\x18\x15 \x01(\x0b\x32..chromiumos.config.api.HardwareFeatures.Button\x12\x45\n\rvolume_button\x18\x16 \x01(\x0b\x32..chromiumos.config.api.HardwareFeatures.Button\x12W\n\x13\x65mbedded_controller\x18\x18 \x01(\x0b\x32:.chromiumos.config.api.HardwareFeatures.EmbeddedController\x12^\n\x17trusted_platform_module\x18\x19 \x01(\x0b\x32=.chromiumos.config.api.HardwareFeatures.TrustedPlatformModule\x12\x46\n\nhotwording\x18\x1a \x01(\x0b\x32\x32.chromiumos.config.api.HardwareFeatures.Hotwording\x12@\n\x07\x64isplay\x18\x1b \x01(\x0b\x32/.chromiumos.config.api.HardwareFeatures.Display\x12\x42\n\x08touchpad\x18\x1c \x01(\x0b\x32\x30.chromiumos.config.api.HardwareFeatures.Touchpad\x12\\\n\x16microphone_mute_switch\x18\x1d \x01(\x0b\x32<.chromiumos.config.api.HardwareFeatures.MicrophoneMuteSwitch\x12@\n\x07\x62\x61ttery\x18\x1e \x01(\x0b\x32/.chromiumos.config.api.HardwareFeatures.Battery\x12M\n\x0eprivacy_screen\x18\x1f \x01(\x0b\x32\x35.chromiumos.config.api.HardwareFeatures.PrivacyScreen\x12\x38\n\x03soc\x18  \x01(\x0b\x32+.chromiumos.config.api.HardwareFeatures.Soc\x12R\n\x0c\x64p_converter\x18! \x01(\x0b\x32<.chromiumos.config.api.HardwareFeatures.DisplayPortConverter\x1a\x16\n\x05\x43ount\x12\r\n\x05value\x18\x01 \x01(\r\x1a\x44\n\x04UsbC\x12<\n\x05\x63ount\x18\x01 \x01(\x0b\x32-.chromiumos.config.api.HardwareFeatures.Count\x1a\x44\n\x04UsbA\x12<\n\x05\x63ount\x18\x01 \x01(\x0b\x32-.chromiumos.config.api.HardwareFeatures.Count\x1aV\n\x03Lte\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12\r\n\x05model\x18\x02 \x01(\t\x1aH\n\x04Hdmi\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\x34\n\x15\x46irmwareConfiguration\x12\r\n\x05value\x18\x01 \x01(\r\x12\x0c\n\x04mask\x18\x02 \x01(\r\x1a\x89\x06\n\x05\x41udio\x12M\n\x0b\x61udio_codec\x18\x01 \x01(\x0e\x32\x38.chromiumos.config.api.HardwareFeatures.Audio.AudioCodec\x12L\n\x0bspeaker_amp\x18\x02 \x01(\x0e\x32\x37.chromiumos.config.api.HardwareFeatures.Audio.Amplifier\x12Q\n\x0fheadphone_codec\x18\x03 \x01(\x0e\x32\x38.chromiumos.config.api.HardwareFeatures.Audio.AudioCodec\x12\x45\n\x0elid_microphone\x18\x04 \x01(\x0b\x32-.chromiumos.config.api.HardwareFeatures.Count\x12\x46\n\x0f\x62\x61se_microphone\x18\x05 \x01(\x0b\x32-.chromiumos.config.api.HardwareFeatures.Count\x12\x45\n\x11speaker_amplifier\x18\x06 \x01(\x0b\x32*.chromiumos.config.api.Component.Amplifier\"\x9d\x01\n\nAudioCodec\x12\x17\n\x13\x41UDIO_CODEC_UNKNOWN\x10\x00\x12\n\n\x06RT5682\x10\x01\x12\x0c\n\x08\x41LC5682I\x10\x02\x12\x0b\n\x07\x41LC5682\x10\x03\x12\n\n\x06\x44\x41\x37\x32\x31\x39\x10\x08\x12\r\n\tNAU88L25B\x10\n\x12\x0b\n\x07\x43S42L42\x10\x0b\x12\x0e\n\nALC5682IVS\x10\x0c\x12\x0b\n\x07WCD9385\x10\r\"\x04\x08\x04\x10\x07\"\x04\x08\t\x10\t\"\x99\x01\n\tAmplifier\x12\x15\n\x11\x41MPLIFIER_UNKNOWN\x10\x00\x12\x0c\n\x08MAX98357\x10\x04\x12\x0c\n\x08MAX98373\x10\x05\x12\x0c\n\x08MAX98360\x10\x06\x12\n\n\x06RT1015\x10\x07\x12\x0b\n\x07\x41LC1011\x10\t\x12\x0b\n\x07RT1015P\x10\n\x12\x0b\n\x07\x41LC1019\x10\x0b\x12\x0c\n\x08MAX98390\x10\x0c\"\x04\x08\x01\x10\x03\"\x04\x08\x08\x10\x08\x1a\xf9\x05\n\x06\x43\x61mera\x12\x46\n\x07\x64\x65vices\x18\x04 \x03(\x0b\x32\x35.chromiumos.config.api.HardwareFeatures.Camera.Device\x1a\xd2\x02\n\x06\x44\x65vice\x12K\n\tinterface\x18\x02 \x01(\x0e\x32\x38.chromiumos.config.api.HardwareFeatures.Camera.Interface\x12\x45\n\x06\x66\x61\x63ing\x18\x03 \x01(\x0e\x32\x35.chromiumos.config.api.HardwareFeatures.Camera.Facing\x12O\n\x0borientation\x18\x04 \x01(\x0e\x32:.chromiumos.config.api.HardwareFeatures.Camera.Orientation\x12\r\n\x05\x66lags\x18\x05 \x01(\r\x12\x0b\n\x03ids\x18\x06 \x03(\t\x12G\n\x0eprivacy_switch\x18\x07 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\"I\n\tInterface\x12\x15\n\x11INTERFACE_UNKNOWN\x10\x00\x12\x11\n\rINTERFACE_USB\x10\x01\x12\x12\n\x0eINTERFACE_MIPI\x10\x02\"?\n\x06\x46\x61\x63ing\x12\x12\n\x0e\x46\x41\x43ING_UNKNOWN\x10\x00\x12\x10\n\x0c\x46\x41\x43ING_FRONT\x10\x01\x12\x0f\n\x0b\x46\x41\x43ING_BACK\x10\x02\"w\n\x0bOrientation\x12\x17\n\x13ORIENTATION_UNKNOWN\x10\x00\x12\x11\n\rORIENTATION_0\x10\x01\x12\x12\n\x0eORIENTATION_90\x10\x02\x12\x13\n\x0fORIENTATION_180\x10\x03\x12\x13\n\x0fORIENTATION_270\x10\x04\"M\n\x05\x46lags\x12\x0e\n\nFLAGS_NONE\x10\x00\x12\x17\n\x13\x46LAGS_SUPPORT_1080P\x10\x01\x12\x1b\n\x17\x46LAGS_SUPPORT_AUTOFOCUS\x10\x02\x1a\xa8\x01\n\rAccelerometer\x12J\n\x11lid_accelerometer\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12K\n\x12\x62\x61se_accelerometer\x18\x02 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\x9c\x01\n\tGyroscope\x12\x46\n\rlid_gyroscope\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12G\n\x0e\x62\x61se_gyroscope\x18\x02 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\xa5\x01\n\x0cMagnetometer\x12I\n\x10lid_magnetometer\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12J\n\x11\x62\x61se_magnetometer\x18\x02 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\xa2\x01\n\x0bLightSensor\x12H\n\x0flid_lightsensor\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12I\n\x10\x62\x61se_lightsensor\x18\x02 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\xaa\x01\n\x06Screen\x12R\n\x10panel_properties\x18\x03 \x01(\x0b\x32\x38.chromiumos.config.api.Component.DisplayPanel.Properties\x12\x46\n\rtouch_support\x18\x02 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.PresentJ\x04\x08\x01\x10\x02\x1a\xff\x01\n\nFormFactor\x12V\n\x0b\x66orm_factor\x18\x01 \x01(\x0e\x32\x41.chromiumos.config.api.HardwareFeatures.FormFactor.FormFactorType\"\x98\x01\n\x0e\x46ormFactorType\x12\x17\n\x13\x46ORM_FACTOR_UNKNOWN\x10\x00\x12\r\n\tCLAMSHELL\x10\x01\x12\x0f\n\x0b\x43ONVERTIBLE\x10\x02\x12\x0e\n\nDETACHABLE\x10\x03\x12\x0e\n\nCHROMEBASE\x10\x04\x12\r\n\tCHROMEBOX\x10\x05\x12\r\n\tCHROMEBIT\x10\x06\x12\x0f\n\x0b\x43HROMESLATE\x10\x07\x1a\x9b\x01\n\x06Stylus\x12I\n\x06stylus\x18\x01 \x01(\x0e\x32\x39.chromiumos.config.api.HardwareFeatures.Stylus.StylusType\"F\n\nStylusType\x12\x12\n\x0eSTYLUS_UNKNOWN\x10\x00\x12\x08\n\x04NONE\x10\x01\x12\x0c\n\x08INTERNAL\x10\x02\x12\x0c\n\x08\x45XTERNAL\x10\x03\x1a\x84\x03\n\x08Keyboard\x12T\n\rkeyboard_type\x18\x01 \x01(\x0e\x32=.chromiumos.config.api.HardwareFeatures.Keyboard.KeyboardType\x12\x42\n\tbacklight\x18\x02 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12\x45\n\x0cpower_button\x18\x03 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12\x44\n\x0bnumeric_pad\x18\x04 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\"Q\n\x0cKeyboardType\x12\x19\n\x15KEYBOARD_TYPE_UNKNOWN\x10\x00\x12\x0c\n\x08INTERNAL\x10\x01\x12\x08\n\x04NONE\x10\x02\x12\x0e\n\nDETACHABLE\x10\x03\x1aJ\n\x06Memory\x12@\n\x07profile\x18\x01 \x01(\x0b\x32/.chromiumos.config.api.Component.Memory.Profile\x1a\xc8\x02\n\x0b\x46ingerprint\x12N\n\x08location\x18\x01 \x01(\x0e\x32<.chromiumos.config.api.HardwareFeatures.Fingerprint.Location\x12\r\n\x05\x62oard\x18\x02 \x01(\t\x12\x12\n\nro_version\x18\x03 \x01(\t\"\xc5\x01\n\x08Location\x12\x14\n\x10LOCATION_UNKNOWN\x10\x00\x12\x19\n\x15POWER_BUTTON_TOP_LEFT\x10\x01\x12\x18\n\x14KEYBOARD_BOTTOM_LEFT\x10\x02\x12\x19\n\x15KEYBOARD_BOTTOM_RIGHT\x10\x03\x12\x16\n\x12KEYBOARD_TOP_RIGHT\x10\x04\x12\x0f\n\x0bNOT_PRESENT\x10\x05\x12\x0e\n\nRIGHT_SIDE\x10\x06\x12\r\n\tLEFT_SIDE\x10\x07\x12\x0b\n\x07PRESENT\x10\x08\x1a\x66\n\x07Storage\x12J\n\x0cstorage_type\x18\x01 \x01(\x0e\x32\x34.chromiumos.config.api.Component.Storage.StorageType\x12\x0f\n\x07size_gb\x18\x02 \x01(\r\x1a\x8c\x01\n\tBluetooth\x12=\n\tcomponent\x18\x01 \x01(\x0b\x32*.chromiumos.config.api.Component.Bluetooth\x12@\n\x07present\x18\x02 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1aN\n\nBarrelJack\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\xf7\x01\n\x04Wifi\x12T\n\x18supported_wlan_protocols\x18\x01 \x03(\x0e\x32\x32.chromiumos.config.api.Component.Wifi.WLANProtocol\x12I\n\nwifi_chips\x18\x02 \x03(\x0e\x32\x35.chromiumos.config.api.HardwareFeatures.Wifi.WifiChip\"N\n\x08WifiChip\x12\x15\n\x11WIFI_CHIP_UNKNOWN\x10\x00\x12\x15\n\x11WIRELESS_86ED801D\x10\x01\x12\x14\n\x10WIRELESS_REALTEK\x10\x02\x1a\xa0\x02\n\x06\x42utton\x12\x45\n\x06region\x18\x01 \x01(\x0e\x32\x35.chromiumos.config.api.HardwareFeatures.Button.Region\x12\x41\n\x04\x65\x64ge\x18\x02 \x01(\x0e\x32\x33.chromiumos.config.api.HardwareFeatures.Button.Edge\x12\x10\n\x08position\x18\x03 \x01(\x02\"6\n\x06Region\x12\x12\n\x0eREGION_UNKNOWN\x10\x00\x12\n\n\x06SCREEN\x10\x01\x12\x0c\n\x08KEYBOARD\x10\x02\"B\n\x04\x45\x64ge\x12\x10\n\x0c\x45\x44GE_UNKNOWN\x10\x00\x12\x08\n\x04LEFT\x10\x01\x12\t\n\x05RIGHT\x10\x02\x12\x07\n\x03TOP\x10\x03\x12\n\n\x06\x42OTTOM\x10\x04\x1a\xc9\x02\n\x12\x45mbeddedController\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12\x62\n\x07\x65\x63_type\x18\x02 \x01(\x0e\x32Q.chromiumos.config.api.HardwareFeatures.EmbeddedController.EmbeddedControllerType\x12\x41\n\x04part\x18\x03 \x01(\x0b\x32\x33.chromiumos.config.api.Component.EmbeddedController\"J\n\x16\x45mbeddedControllerType\x12\x13\n\x0f\x45\x43_TYPE_UNKNOWN\x10\x00\x12\r\n\tEC_CHROME\x10\x01\x12\x0c\n\x08\x45\x43_WILCO\x10\x02\x1a\xe0\x01\n\x15TrustedPlatformModule\x12i\n\x08tpm_type\x18\x01 \x01(\x0e\x32W.chromiumos.config.api.HardwareFeatures.TrustedPlatformModule.TrustedPlatformModuleType\"\\\n\x19TrustedPlatformModuleType\x12\x14\n\x10TPM_TYPE_UNKNOWN\x10\x00\x12\x0f\n\x0bTHIRD_PARTY\x10\x01\x12\x0b\n\x07GSC_H1B\x10\x02\x12\x0b\n\x07GSC_H1D\x10\x03\x1aN\n\nHotwording\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\xa9\x01\n\x07\x44isplay\x12\x42\n\x04type\x18\x01 \x01(\x0e\x32\x34.chromiumos.config.api.HardwareFeatures.Display.Type\"Z\n\x04Type\x12\x10\n\x0cTYPE_UNKNOWN\x10\x00\x12\x11\n\rTYPE_INTERNAL\x10\x01\x12\x11\n\rTYPE_EXTERNAL\x10\x02\x12\x1a\n\x16TYPE_INTERNAL_EXTERNAL\x10\x03\x1aL\n\x08Touchpad\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1aX\n\x14MicrophoneMuteSwitch\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\xb6\x05\n\x07\x42\x61ttery\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12J\n\x08lifetime\x18\x02 \x01(\x0b\x32\x38.chromiumos.config.api.HardwareFeatures.Battery.Lifetime\x12J\n\x08\x63harging\x18\x03 \x01(\x0b\x32\x38.chromiumos.config.api.HardwareFeatures.Battery.Charging\x1a\x9f\x02\n\x08Lifetime\x12\x35\n\x0cshipping_min\x18\x01 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x12\x37\n\x0e\x64\x65\x65p_sleep_min\x18\x02 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x12\x34\n\x0bsuspend_min\x18\x03 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x12\x38\n\x0flucid_sleep_min\x18\x04 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x12\x33\n\nactive_min\x18\x05 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x1a\xae\x01\n\x08\x43harging\x12\x33\n\nactive_max\x18\x01 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x12\x34\n\x0bsuspend_max\x18\x02 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x12\x37\n\x0e\x64\x65\x65p_sleep_max\x18\x03 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x1aQ\n\rPrivacyScreen\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\x45\n\x03Soc\x12>\n\x08\x66\x65\x61tures\x18\x01 \x03(\x0e\x32,.chromiumos.config.api.Component.Soc.Feature\x1a\x61\n\x14\x44isplayPortConverter\x12I\n\nconverters\x18\x01 \x03(\x0b\x32\x35.chromiumos.config.api.Component.DisplayPortConverter\"<\n\x07Present\x12\x13\n\x0fPRESENT_UNKNOWN\x10\x00\x12\x0b\n\x07PRESENT\x10\x01\x12\x0f\n\x0bNOT_PRESENT\x10\x02\x42*Z(go.chromium.org/chromiumos/config/go/apib\x06proto3'
+  serialized_pb=b'\n$chromiumos/config/api/topology.proto\x12\x15\x63hromiumos.config.api\x1a%chromiumos/config/api/component.proto\x1a\x1egoogle/protobuf/wrappers.proto\"\x9a\x06\n\x08Topology\x12\n\n\x02id\x18\x01 \x01(\t\x12\x32\n\x04type\x18\x02 \x01(\x0e\x32$.chromiumos.config.api.Topology.Type\x12\x45\n\x0b\x64\x65scription\x18\x03 \x03(\x0b\x32\x30.chromiumos.config.api.Topology.DescriptionEntry\x12\x41\n\x10hardware_feature\x18\x04 \x01(\x0b\x32\'.chromiumos.config.api.HardwareFeatures\x1a\x32\n\x10\x44\x65scriptionEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x8f\x04\n\x04Type\x12\x10\n\x0cTYPE_UNKNOWN\x10\x00\x12\n\n\x06SCREEN\x10\x01\x12\x0f\n\x0b\x46ORM_FACTOR\x10\x02\x12\t\n\x05\x41UDIO\x10\x03\x12\n\n\x06STYLUS\x10\x04\x12\x0c\n\x08KEYBOARD\x10\x05\x12\x0b\n\x07THERMAL\x10\x06\x12\n\n\x06\x43\x41MERA\x10\x07\x12(\n$ACCELEROMETER_GYROSCOPE_MAGNETOMETER\x10\x08\x12\x0f\n\x0b\x46INGERPRINT\x10\t\x12\x14\n\x10PROXIMITY_SENSOR\x10\n\x12\x12\n\x0e\x44\x41UGHTER_BOARD\x10\x0b\x12\x18\n\x14NON_VOLATILE_STORAGE\x10\x0c\x12\x07\n\x03RAM\x10\r\x12\x08\n\x04WIFI\x10\x0e\x12\x12\n\x0e\x43\x45LLULAR_BOARD\x10\x0f\x12\r\n\tSD_READER\x10\x10\x12\x13\n\x0fMOTHERBOARD_USB\x10\x11\x12\r\n\tBLUETOOTH\x10\x12\x12\x0e\n\nBARRELJACK\x10\x13\x12\x10\n\x0cPOWER_BUTTON\x10\x14\x12\x11\n\rVOLUME_BUTTON\x10\x15\x12\x06\n\x02\x45\x43\x10\x16\x12\t\n\x05TOUCH\x10\x17\x12\x07\n\x03TPM\x10\x18\x12\x1a\n\x16MICROPHONE_MUTE_SWITCH\x10\x19\x12\x0b\n\x07\x42\x41TTERY\x10\x1a\x12\x08\n\x04HDMI\x10\x1b\x12\x07\n\x03SOC\x10\x1c\x12\x07\n\x03HPS\x10\x1d\x12\x10\n\x0c\x44P_CONVERTER\x10\x1e\x12\x07\n\x03POE\x10\x1f\x12\x10\n\x0cPOWER_SUPPLY\x10 \"\xa8\x01\n\x08\x44uration\x12\x32\n\x04type\x18\x01 \x01(\x0e\x32$.chromiumos.config.api.Duration.Type\x12\r\n\x05value\x18\x02 \x01(\x05\"Y\n\x04Type\x12\x10\n\x0cTYPE_UNKNOWN\x10\x00\x12\x10\n\x0cMILLISECONDS\x10\x01\x12\x0b\n\x07SECONDS\x10\x02\x12\x0b\n\x07MINUTES\x10\x03\x12\t\n\x05HOURS\x10\x04\x12\x08\n\x04\x44\x41YS\x10\x05\"\xeaR\n\x10HardwareFeatures\x12;\n\x05usb_c\x18\x01 \x01(\x0b\x32,.chromiumos.config.api.HardwareFeatures.UsbC\x12;\n\x05usb_a\x18\x02 \x01(\x0b\x32,.chromiumos.config.api.HardwareFeatures.UsbA\x12\x42\n\x08\x63\x65llular\x18\x03 \x01(\x0b\x32\x30.chromiumos.config.api.HardwareFeatures.Cellular\x12:\n\x04hdmi\x18\x04 \x01(\x0b\x32,.chromiumos.config.api.HardwareFeatures.Hdmi\x12P\n\tfw_config\x18\x05 \x01(\x0b\x32=.chromiumos.config.api.HardwareFeatures.FirmwareConfiguration\x12<\n\x05\x61udio\x18\x06 \x01(\x0b\x32-.chromiumos.config.api.HardwareFeatures.Audio\x12>\n\x06\x63\x61mera\x18\x07 \x01(\x0b\x32..chromiumos.config.api.HardwareFeatures.Camera\x12L\n\raccelerometer\x18\x08 \x01(\x0b\x32\x35.chromiumos.config.api.HardwareFeatures.Accelerometer\x12\x44\n\tgyroscope\x18\t \x01(\x0b\x32\x31.chromiumos.config.api.HardwareFeatures.Gyroscope\x12J\n\x0cmagnetometer\x18\n \x01(\x0b\x32\x34.chromiumos.config.api.HardwareFeatures.Magnetometer\x12I\n\x0clight_sensor\x18\x0b \x01(\x0b\x32\x33.chromiumos.config.api.HardwareFeatures.LightSensor\x12>\n\x06screen\x18\x0c \x01(\x0b\x32..chromiumos.config.api.HardwareFeatures.Screen\x12G\n\x0b\x66orm_factor\x18\r \x01(\x0b\x32\x32.chromiumos.config.api.HardwareFeatures.FormFactor\x12>\n\x06stylus\x18\x0e \x01(\x0b\x32..chromiumos.config.api.HardwareFeatures.Stylus\x12\x42\n\x08keyboard\x18\x0f \x01(\x0b\x32\x30.chromiumos.config.api.HardwareFeatures.Keyboard\x12>\n\x06memory\x18\x10 \x01(\x0b\x32..chromiumos.config.api.HardwareFeatures.Memory\x12H\n\x0b\x66ingerprint\x18\x11 \x01(\x0b\x32\x33.chromiumos.config.api.HardwareFeatures.Fingerprint\x12@\n\x07storage\x18\x12 \x01(\x0b\x32/.chromiumos.config.api.HardwareFeatures.Storage\x12\x44\n\tbluetooth\x18\x13 \x01(\x0b\x32\x31.chromiumos.config.api.HardwareFeatures.Bluetooth\x12\x46\n\nbarreljack\x18\x14 \x01(\x0b\x32\x32.chromiumos.config.api.HardwareFeatures.BarrelJack\x12:\n\x04wifi\x18\x17 \x01(\x0b\x32,.chromiumos.config.api.HardwareFeatures.Wifi\x12\x44\n\x0cpower_button\x18\x15 \x01(\x0b\x32..chromiumos.config.api.HardwareFeatures.Button\x12\x45\n\rvolume_button\x18\x16 \x01(\x0b\x32..chromiumos.config.api.HardwareFeatures.Button\x12W\n\x13\x65mbedded_controller\x18\x18 \x01(\x0b\x32:.chromiumos.config.api.HardwareFeatures.EmbeddedController\x12^\n\x17trusted_platform_module\x18\x19 \x01(\x0b\x32=.chromiumos.config.api.HardwareFeatures.TrustedPlatformModule\x12\x46\n\nhotwording\x18\x1a \x01(\x0b\x32\x32.chromiumos.config.api.HardwareFeatures.Hotwording\x12@\n\x07\x64isplay\x18\x1b \x01(\x0b\x32/.chromiumos.config.api.HardwareFeatures.Display\x12\x42\n\x08touchpad\x18\x1c \x01(\x0b\x32\x30.chromiumos.config.api.HardwareFeatures.Touchpad\x12\\\n\x16microphone_mute_switch\x18\x1d \x01(\x0b\x32<.chromiumos.config.api.HardwareFeatures.MicrophoneMuteSwitch\x12@\n\x07\x62\x61ttery\x18\x1e \x01(\x0b\x32/.chromiumos.config.api.HardwareFeatures.Battery\x12M\n\x0eprivacy_screen\x18\x1f \x01(\x0b\x32\x35.chromiumos.config.api.HardwareFeatures.PrivacyScreen\x12\x38\n\x03soc\x18  \x01(\x0b\x32+.chromiumos.config.api.HardwareFeatures.Soc\x12R\n\x0c\x64p_converter\x18! \x01(\x0b\x32<.chromiumos.config.api.HardwareFeatures.DisplayPortConverter\x12\x38\n\x03hps\x18\" \x01(\x0b\x32+.chromiumos.config.api.HardwareFeatures.Hps\x12\x38\n\x03poe\x18# \x01(\x0b\x32+.chromiumos.config.api.HardwareFeatures.PoE\x12I\n\x0cpower_supply\x18$ \x01(\x0b\x32\x33.chromiumos.config.api.HardwareFeatures.PowerSupply\x1a\x16\n\x05\x43ount\x12\r\n\x05value\x18\x01 \x01(\r\x1a\x44\n\x04UsbC\x12<\n\x05\x63ount\x18\x01 \x01(\x0b\x32-.chromiumos.config.api.HardwareFeatures.Count\x1a\x44\n\x04UsbA\x12<\n\x05\x63ount\x18\x01 \x01(\x0b\x32-.chromiumos.config.api.HardwareFeatures.Count\x1a\x89\x02\n\x08\x43\x65llular\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12\r\n\x05model\x18\x02 \x01(\t\x12K\n\x04type\x18\x03 \x01(\x0e\x32=.chromiumos.config.api.HardwareFeatures.Cellular.CellularType\x12\x1b\n\x13\x61ttach_apn_required\x18\x04 \x01(\x08\"B\n\x0c\x43\x65llularType\x12\x0f\n\x0bNOT_PRESENT\x10\x00\x12\x10\n\x0c\x43\x45LLULAR_LTE\x10\x01\x12\x0f\n\x0b\x43\x45LLULAR_5G\x10\x02\x1aH\n\x04Hdmi\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\x34\n\x15\x46irmwareConfiguration\x12\r\n\x05value\x18\x01 \x01(\r\x12\x0c\n\x04mask\x18\x02 \x01(\r\x1a\xec\n\n\x05\x41udio\x12M\n\x0b\x61udio_codec\x18\x01 \x01(\x0e\x32\x38.chromiumos.config.api.HardwareFeatures.Audio.AudioCodec\x12L\n\x0bspeaker_amp\x18\x02 \x01(\x0e\x32\x37.chromiumos.config.api.HardwareFeatures.Audio.Amplifier\x12Q\n\x0fheadphone_codec\x18\x03 \x01(\x0e\x32\x38.chromiumos.config.api.HardwareFeatures.Audio.AudioCodec\x12\x45\n\x0elid_microphone\x18\x04 \x01(\x0b\x32-.chromiumos.config.api.HardwareFeatures.Count\x12\x46\n\x0f\x62\x61se_microphone\x18\x05 \x01(\x0b\x32-.chromiumos.config.api.HardwareFeatures.Count\x12\x45\n\x11speaker_amplifier\x18\x06 \x01(\x0b\x32*.chromiumos.config.api.Component.Amplifier\x12N\n\x0c\x63\x61rd_configs\x18\x07 \x03(\x0b\x32\x38.chromiumos.config.api.HardwareFeatures.Audio.CardConfig\x12W\n\x0b\x63ras_config\x18\x08 \x01(\x0e\x32\x42.chromiumos.config.api.HardwareFeatures.Audio.AudioConfigStructure\x1a\xe6\x02\n\nCardConfig\x12\x11\n\tcard_name\x18\x01 \x01(\t\x12\x30\n\nucm_suffix\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12V\n\nucm_config\x18\x03 \x01(\x0e\x32\x42.chromiumos.config.api.HardwareFeatures.Audio.AudioConfigStructure\x12W\n\x0b\x63ras_config\x18\x04 \x01(\x0e\x32\x42.chromiumos.config.api.HardwareFeatures.Audio.AudioConfigStructure\x12\x62\n\x16sound_card_init_config\x18\x05 \x01(\x0e\x32\x42.chromiumos.config.api.HardwareFeatures.Audio.AudioConfigStructure\"\x9d\x01\n\nAudioCodec\x12\x17\n\x13\x41UDIO_CODEC_UNKNOWN\x10\x00\x12\n\n\x06RT5682\x10\x01\x12\x0c\n\x08\x41LC5682I\x10\x02\x12\x0b\n\x07\x41LC5682\x10\x03\x12\n\n\x06\x44\x41\x37\x32\x31\x39\x10\x08\x12\r\n\tNAU88L25B\x10\n\x12\x0b\n\x07\x43S42L42\x10\x0b\x12\x0e\n\nALC5682IVS\x10\x0c\x12\x0b\n\x07WCD9385\x10\r\"\x04\x08\x04\x10\x07\"\x04\x08\t\x10\t\"\x99\x01\n\tAmplifier\x12\x15\n\x11\x41MPLIFIER_UNKNOWN\x10\x00\x12\x0c\n\x08MAX98357\x10\x04\x12\x0c\n\x08MAX98373\x10\x05\x12\x0c\n\x08MAX98360\x10\x06\x12\n\n\x06RT1015\x10\x07\x12\x0b\n\x07\x41LC1011\x10\t\x12\x0b\n\x07RT1015P\x10\n\x12\x0b\n\x07\x41LC1019\x10\x0b\x12\x0c\n\x08MAX98390\x10\x0c\"\x04\x08\x01\x10\x03\"\x04\x08\x08\x10\x08\"O\n\x14\x41udioConfigStructure\x12\x1f\n\x1b\x41UDIO_CONFIG_STRUCTURE_NONE\x10\x00\x12\n\n\x06\x44\x45SIGN\x10\x01\x12\n\n\x06\x43OMMON\x10\x02\x1a\xf9\x05\n\x06\x43\x61mera\x12\x46\n\x07\x64\x65vices\x18\x04 \x03(\x0b\x32\x35.chromiumos.config.api.HardwareFeatures.Camera.Device\x1a\xd2\x02\n\x06\x44\x65vice\x12K\n\tinterface\x18\x02 \x01(\x0e\x32\x38.chromiumos.config.api.HardwareFeatures.Camera.Interface\x12\x45\n\x06\x66\x61\x63ing\x18\x03 \x01(\x0e\x32\x35.chromiumos.config.api.HardwareFeatures.Camera.Facing\x12O\n\x0borientation\x18\x04 \x01(\x0e\x32:.chromiumos.config.api.HardwareFeatures.Camera.Orientation\x12\r\n\x05\x66lags\x18\x05 \x01(\r\x12\x0b\n\x03ids\x18\x06 \x03(\t\x12G\n\x0eprivacy_switch\x18\x07 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\"I\n\tInterface\x12\x15\n\x11INTERFACE_UNKNOWN\x10\x00\x12\x11\n\rINTERFACE_USB\x10\x01\x12\x12\n\x0eINTERFACE_MIPI\x10\x02\"?\n\x06\x46\x61\x63ing\x12\x12\n\x0e\x46\x41\x43ING_UNKNOWN\x10\x00\x12\x10\n\x0c\x46\x41\x43ING_FRONT\x10\x01\x12\x0f\n\x0b\x46\x41\x43ING_BACK\x10\x02\"w\n\x0bOrientation\x12\x17\n\x13ORIENTATION_UNKNOWN\x10\x00\x12\x11\n\rORIENTATION_0\x10\x01\x12\x12\n\x0eORIENTATION_90\x10\x02\x12\x13\n\x0fORIENTATION_180\x10\x03\x12\x13\n\x0fORIENTATION_270\x10\x04\"M\n\x05\x46lags\x12\x0e\n\nFLAGS_NONE\x10\x00\x12\x17\n\x13\x46LAGS_SUPPORT_1080P\x10\x01\x12\x1b\n\x17\x46LAGS_SUPPORT_AUTOFOCUS\x10\x02\x1a\xa8\x01\n\rAccelerometer\x12J\n\x11lid_accelerometer\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12K\n\x12\x62\x61se_accelerometer\x18\x02 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\x9c\x01\n\tGyroscope\x12\x46\n\rlid_gyroscope\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12G\n\x0e\x62\x61se_gyroscope\x18\x02 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\xa5\x01\n\x0cMagnetometer\x12I\n\x10lid_magnetometer\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12J\n\x11\x62\x61se_magnetometer\x18\x02 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\xa2\x01\n\x0bLightSensor\x12H\n\x0flid_lightsensor\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12I\n\x10\x62\x61se_lightsensor\x18\x02 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\xaa\x01\n\x06Screen\x12R\n\x10panel_properties\x18\x03 \x01(\x0b\x32\x38.chromiumos.config.api.Component.DisplayPanel.Properties\x12\x46\n\rtouch_support\x18\x02 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.PresentJ\x04\x08\x01\x10\x02\x1a\xff\x01\n\nFormFactor\x12V\n\x0b\x66orm_factor\x18\x01 \x01(\x0e\x32\x41.chromiumos.config.api.HardwareFeatures.FormFactor.FormFactorType\"\x98\x01\n\x0e\x46ormFactorType\x12\x17\n\x13\x46ORM_FACTOR_UNKNOWN\x10\x00\x12\r\n\tCLAMSHELL\x10\x01\x12\x0f\n\x0b\x43ONVERTIBLE\x10\x02\x12\x0e\n\nDETACHABLE\x10\x03\x12\x0e\n\nCHROMEBASE\x10\x04\x12\r\n\tCHROMEBOX\x10\x05\x12\r\n\tCHROMEBIT\x10\x06\x12\x0f\n\x0b\x43HROMESLATE\x10\x07\x1a\x9b\x01\n\x06Stylus\x12I\n\x06stylus\x18\x01 \x01(\x0e\x32\x39.chromiumos.config.api.HardwareFeatures.Stylus.StylusType\"F\n\nStylusType\x12\x12\n\x0eSTYLUS_UNKNOWN\x10\x00\x12\x08\n\x04NONE\x10\x01\x12\x0c\n\x08INTERNAL\x10\x02\x12\x0c\n\x08\x45XTERNAL\x10\x03\x1a\xa2\x03\n\x08Keyboard\x12T\n\rkeyboard_type\x18\x01 \x01(\x0e\x32=.chromiumos.config.api.HardwareFeatures.Keyboard.KeyboardType\x12\x42\n\tbacklight\x18\x02 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12\x45\n\x0cpower_button\x18\x03 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12\x44\n\x0bnumeric_pad\x18\x04 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12\x1c\n\x14\x62\x61\x63klight_user_steps\x18\x05 \x03(\x01\"Q\n\x0cKeyboardType\x12\x19\n\x15KEYBOARD_TYPE_UNKNOWN\x10\x00\x12\x0c\n\x08INTERNAL\x10\x01\x12\x08\n\x04NONE\x10\x02\x12\x0e\n\nDETACHABLE\x10\x03\x1aJ\n\x06Memory\x12@\n\x07profile\x18\x01 \x01(\x0b\x32/.chromiumos.config.api.Component.Memory.Profile\x1a\xc8\x02\n\x0b\x46ingerprint\x12N\n\x08location\x18\x01 \x01(\x0e\x32<.chromiumos.config.api.HardwareFeatures.Fingerprint.Location\x12\r\n\x05\x62oard\x18\x02 \x01(\t\x12\x12\n\nro_version\x18\x03 \x01(\t\"\xc5\x01\n\x08Location\x12\x14\n\x10LOCATION_UNKNOWN\x10\x00\x12\x19\n\x15POWER_BUTTON_TOP_LEFT\x10\x01\x12\x18\n\x14KEYBOARD_BOTTOM_LEFT\x10\x02\x12\x19\n\x15KEYBOARD_BOTTOM_RIGHT\x10\x03\x12\x16\n\x12KEYBOARD_TOP_RIGHT\x10\x04\x12\x0f\n\x0bNOT_PRESENT\x10\x05\x12\x0e\n\nRIGHT_SIDE\x10\x06\x12\r\n\tLEFT_SIDE\x10\x07\x12\x0b\n\x07PRESENT\x10\x08\x1a\x66\n\x07Storage\x12J\n\x0cstorage_type\x18\x01 \x01(\x0e\x32\x34.chromiumos.config.api.Component.Storage.StorageType\x12\x0f\n\x07size_gb\x18\x02 \x01(\r\x1a\x8c\x01\n\tBluetooth\x12=\n\tcomponent\x18\x01 \x01(\x0b\x32*.chromiumos.config.api.Component.Bluetooth\x12@\n\x07present\x18\x02 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1aN\n\nBarrelJack\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\xf7\x01\n\x04Wifi\x12T\n\x18supported_wlan_protocols\x18\x01 \x03(\x0e\x32\x32.chromiumos.config.api.Component.Wifi.WLANProtocol\x12I\n\nwifi_chips\x18\x02 \x03(\x0e\x32\x35.chromiumos.config.api.HardwareFeatures.Wifi.WifiChip\"N\n\x08WifiChip\x12\x15\n\x11WIFI_CHIP_UNKNOWN\x10\x00\x12\x15\n\x11WIRELESS_86ED801D\x10\x01\x12\x14\n\x10WIRELESS_REALTEK\x10\x02\x1a\xa0\x02\n\x06\x42utton\x12\x45\n\x06region\x18\x01 \x01(\x0e\x32\x35.chromiumos.config.api.HardwareFeatures.Button.Region\x12\x41\n\x04\x65\x64ge\x18\x02 \x01(\x0e\x32\x33.chromiumos.config.api.HardwareFeatures.Button.Edge\x12\x10\n\x08position\x18\x03 \x01(\x02\"6\n\x06Region\x12\x12\n\x0eREGION_UNKNOWN\x10\x00\x12\n\n\x06SCREEN\x10\x01\x12\x0c\n\x08KEYBOARD\x10\x02\"B\n\x04\x45\x64ge\x12\x10\n\x0c\x45\x44GE_UNKNOWN\x10\x00\x12\x08\n\x04LEFT\x10\x01\x12\t\n\x05RIGHT\x10\x02\x12\x07\n\x03TOP\x10\x03\x12\n\n\x06\x42OTTOM\x10\x04\x1a\xd3\x03\n\x12\x45mbeddedController\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12\x62\n\x07\x65\x63_type\x18\x02 \x01(\x0e\x32Q.chromiumos.config.api.HardwareFeatures.EmbeddedController.EmbeddedControllerType\x12\x41\n\x04part\x18\x03 \x01(\x0b\x32\x33.chromiumos.config.api.Component.EmbeddedController\x12J\n\x11\x66\x65\x61ture_typec_cmd\x18\x04 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12<\n\x03\x63\x62i\x18\x05 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\"J\n\x16\x45mbeddedControllerType\x12\x13\n\x0f\x45\x43_TYPE_UNKNOWN\x10\x00\x12\r\n\tEC_CHROME\x10\x01\x12\x0c\n\x08\x45\x43_WILCO\x10\x02\x1a\xe0\x01\n\x15TrustedPlatformModule\x12i\n\x08tpm_type\x18\x01 \x01(\x0e\x32W.chromiumos.config.api.HardwareFeatures.TrustedPlatformModule.TrustedPlatformModuleType\"\\\n\x19TrustedPlatformModuleType\x12\x14\n\x10TPM_TYPE_UNKNOWN\x10\x00\x12\x0f\n\x0bTHIRD_PARTY\x10\x01\x12\x0b\n\x07GSC_H1B\x10\x02\x12\x0b\n\x07GSC_H1D\x10\x03\x1aN\n\nHotwording\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\xa9\x01\n\x07\x44isplay\x12\x42\n\x04type\x18\x01 \x01(\x0e\x32\x34.chromiumos.config.api.HardwareFeatures.Display.Type\"Z\n\x04Type\x12\x10\n\x0cTYPE_UNKNOWN\x10\x00\x12\x11\n\rTYPE_INTERNAL\x10\x01\x12\x11\n\rTYPE_EXTERNAL\x10\x02\x12\x1a\n\x16TYPE_INTERNAL_EXTERNAL\x10\x03\x1aL\n\x08Touchpad\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1aX\n\x14MicrophoneMuteSwitch\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\xb6\x05\n\x07\x42\x61ttery\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12J\n\x08lifetime\x18\x02 \x01(\x0b\x32\x38.chromiumos.config.api.HardwareFeatures.Battery.Lifetime\x12J\n\x08\x63harging\x18\x03 \x01(\x0b\x32\x38.chromiumos.config.api.HardwareFeatures.Battery.Charging\x1a\x9f\x02\n\x08Lifetime\x12\x35\n\x0cshipping_min\x18\x01 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x12\x37\n\x0e\x64\x65\x65p_sleep_min\x18\x02 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x12\x34\n\x0bsuspend_min\x18\x03 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x12\x38\n\x0flucid_sleep_min\x18\x04 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x12\x33\n\nactive_min\x18\x05 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x1a\xae\x01\n\x08\x43harging\x12\x33\n\nactive_max\x18\x01 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x12\x34\n\x0bsuspend_max\x18\x02 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x12\x37\n\x0e\x64\x65\x65p_sleep_max\x18\x03 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x1aQ\n\rPrivacyScreen\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\x45\n\x03Soc\x12>\n\x08\x66\x65\x61tures\x18\x01 \x03(\x0e\x32,.chromiumos.config.api.Component.Soc.Feature\x1a\x61\n\x14\x44isplayPortConverter\x12I\n\nconverters\x18\x01 \x03(\x0b\x32\x35.chromiumos.config.api.Component.DisplayPortConverter\x1aG\n\x03Hps\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1aG\n\x03PoE\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1al\n\x0bPowerSupply\x12\x43\n\nbarreljack\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12\x18\n\x10usb_min_ac_watts\x18\x02 \x01(\x05\"<\n\x07Present\x12\x13\n\x0fPRESENT_UNKNOWN\x10\x00\x12\x0b\n\x07PRESENT\x10\x01\x12\x0f\n\x0bNOT_PRESENT\x10\x02\x42*Z(go.chromium.org/chromiumos/config/go/apib\x06proto3'
   ,
-  dependencies=[chromiumos_dot_config_dot_api_dot_component__pb2.DESCRIPTOR,])
+  dependencies=[chromiumos_dot_config_dot_api_dot_component__pb2.DESCRIPTOR,google_dot_protobuf_dot_wrappers__pb2.DESCRIPTOR,])
 
 
 
@@ -109,7 +110,7 @@
       type=None,
       create_key=_descriptor._internal_create_key),
     _descriptor.EnumValueDescriptor(
-      name='LTE_BOARD', index=15, number=15,
+      name='CELLULAR_BOARD', index=15, number=15,
       serialized_options=None,
       type=None,
       create_key=_descriptor._internal_create_key),
@@ -178,11 +179,31 @@
       serialized_options=None,
       type=None,
       create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='HPS', index=29, number=29,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='DP_CONVERTER', index=30, number=30,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='POE', index=31, number=31,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='POWER_SUPPLY', index=32, number=32,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=370,
-  serialized_end=838,
+  serialized_start=402,
+  serialized_end=929,
 )
 _sym_db.RegisterEnumDescriptor(_TOPOLOGY_TYPE)
 
@@ -226,11 +247,41 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=920,
-  serialized_end=1009,
+  serialized_start=1011,
+  serialized_end=1100,
 )
 _sym_db.RegisterEnumDescriptor(_DURATION_TYPE)
 
+_HARDWAREFEATURES_CELLULAR_CELLULARTYPE = _descriptor.EnumDescriptor(
+  name='CellularType',
+  full_name='chromiumos.config.api.HardwareFeatures.Cellular.CellularType',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='NOT_PRESENT', index=0, number=0,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='CELLULAR_LTE', index=1, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='CELLULAR_5G', index=2, number=2,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=4023,
+  serialized_end=4089,
+)
+_sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_CELLULAR_CELLULARTYPE)
+
 _HARDWAREFEATURES_AUDIO_AUDIOCODEC = _descriptor.EnumDescriptor(
   name='AudioCodec',
   full_name='chromiumos.config.api.HardwareFeatures.Audio.AudioCodec',
@@ -286,8 +337,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=4212,
-  serialized_end=4369,
+  serialized_start=5214,
+  serialized_end=5371,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_AUDIO_AUDIOCODEC)
 
@@ -346,11 +397,41 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=4372,
-  serialized_end=4525,
+  serialized_start=5374,
+  serialized_end=5527,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_AUDIO_AMPLIFIER)
 
+_HARDWAREFEATURES_AUDIO_AUDIOCONFIGSTRUCTURE = _descriptor.EnumDescriptor(
+  name='AudioConfigStructure',
+  full_name='chromiumos.config.api.HardwareFeatures.Audio.AudioConfigStructure',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='AUDIO_CONFIG_STRUCTURE_NONE', index=0, number=0,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='DESIGN', index=1, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='COMMON', index=2, number=2,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=5529,
+  serialized_end=5608,
+)
+_sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_AUDIO_AUDIOCONFIGSTRUCTURE)
+
 _HARDWAREFEATURES_CAMERA_INTERFACE = _descriptor.EnumDescriptor(
   name='Interface',
   full_name='chromiumos.config.api.HardwareFeatures.Camera.Interface',
@@ -376,8 +457,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=4951,
-  serialized_end=5024,
+  serialized_start=6034,
+  serialized_end=6107,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_CAMERA_INTERFACE)
 
@@ -406,8 +487,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=5026,
-  serialized_end=5089,
+  serialized_start=6109,
+  serialized_end=6172,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_CAMERA_FACING)
 
@@ -446,8 +527,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=5091,
-  serialized_end=5210,
+  serialized_start=6174,
+  serialized_end=6293,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_CAMERA_ORIENTATION)
 
@@ -476,8 +557,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=5212,
-  serialized_end=5289,
+  serialized_start=6295,
+  serialized_end=6372,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_CAMERA_FLAGS)
 
@@ -531,8 +612,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=6231,
-  serialized_end=6383,
+  serialized_start=7314,
+  serialized_end=7466,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_FORMFACTOR_FORMFACTORTYPE)
 
@@ -566,8 +647,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=6471,
-  serialized_end=6541,
+  serialized_start=7554,
+  serialized_end=7624,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_STYLUS_STYLUSTYPE)
 
@@ -601,8 +682,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=6851,
-  serialized_end=6932,
+  serialized_start=7964,
+  serialized_end=8045,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_KEYBOARD_KEYBOARDTYPE)
 
@@ -661,8 +742,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=7142,
-  serialized_end=7339,
+  serialized_start=8255,
+  serialized_end=8452,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_FINGERPRINT_LOCATION)
 
@@ -691,8 +772,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=7838,
-  serialized_end=7916,
+  serialized_start=8951,
+  serialized_end=9029,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_WIFI_WIFICHIP)
 
@@ -721,8 +802,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=8085,
-  serialized_end=8139,
+  serialized_start=9198,
+  serialized_end=9252,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_BUTTON_REGION)
 
@@ -761,8 +842,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=8141,
-  serialized_end=8207,
+  serialized_start=9254,
+  serialized_end=9320,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_BUTTON_EDGE)
 
@@ -791,8 +872,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=8465,
-  serialized_end=8539,
+  serialized_start=9716,
+  serialized_end=9790,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_EMBEDDEDCONTROLLER_EMBEDDEDCONTROLLERTYPE)
 
@@ -826,8 +907,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=8674,
-  serialized_end=8766,
+  serialized_start=9925,
+  serialized_end=10017,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_TRUSTEDPLATFORMMODULE_TRUSTEDPLATFORMMODULETYPE)
 
@@ -861,8 +942,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=8928,
-  serialized_end=9018,
+  serialized_start=10179,
+  serialized_end=10269,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_DISPLAY_TYPE)
 
@@ -891,8 +972,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=10138,
-  serialized_end=10198,
+  serialized_start=11645,
+  serialized_end=11705,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_PRESENT)
 
@@ -931,8 +1012,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=317,
-  serialized_end=367,
+  serialized_start=349,
+  serialized_end=399,
 )
 
 _TOPOLOGY = _descriptor.Descriptor(
@@ -984,8 +1065,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=103,
-  serialized_end=838,
+  serialized_start=135,
+  serialized_end=929,
 )
 
 
@@ -1024,8 +1105,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=841,
-  serialized_end=1009,
+  serialized_start=932,
+  serialized_end=1100,
 )
 
 
@@ -1056,8 +1137,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3367,
-  serialized_end=3389,
+  serialized_start=3659,
+  serialized_end=3681,
 )
 
 _HARDWAREFEATURES_USBC = _descriptor.Descriptor(
@@ -1087,8 +1168,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3391,
-  serialized_end=3459,
+  serialized_start=3683,
+  serialized_end=3751,
 )
 
 _HARDWAREFEATURES_USBA = _descriptor.Descriptor(
@@ -1118,37 +1199,52 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3461,
-  serialized_end=3529,
+  serialized_start=3753,
+  serialized_end=3821,
 )
 
-_HARDWAREFEATURES_LTE = _descriptor.Descriptor(
-  name='Lte',
-  full_name='chromiumos.config.api.HardwareFeatures.Lte',
+_HARDWAREFEATURES_CELLULAR = _descriptor.Descriptor(
+  name='Cellular',
+  full_name='chromiumos.config.api.HardwareFeatures.Cellular',
   filename=None,
   file=DESCRIPTOR,
   containing_type=None,
   create_key=_descriptor._internal_create_key,
   fields=[
     _descriptor.FieldDescriptor(
-      name='present', full_name='chromiumos.config.api.HardwareFeatures.Lte.present', index=0,
+      name='present', full_name='chromiumos.config.api.HardwareFeatures.Cellular.present', index=0,
       number=1, type=14, cpp_type=8, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='model', full_name='chromiumos.config.api.HardwareFeatures.Lte.model', index=1,
+      name='model', full_name='chromiumos.config.api.HardwareFeatures.Cellular.model', index=1,
       number=2, type=9, cpp_type=9, label=1,
       has_default_value=False, default_value=b"".decode('utf-8'),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='type', full_name='chromiumos.config.api.HardwareFeatures.Cellular.type', index=2,
+      number=3, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='attach_apn_required', full_name='chromiumos.config.api.HardwareFeatures.Cellular.attach_apn_required', index=3,
+      number=4, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
   nested_types=[],
   enum_types=[
+    _HARDWAREFEATURES_CELLULAR_CELLULARTYPE,
   ],
   serialized_options=None,
   is_extendable=False,
@@ -1156,8 +1252,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3531,
-  serialized_end=3617,
+  serialized_start=3824,
+  serialized_end=4089,
 )
 
 _HARDWAREFEATURES_HDMI = _descriptor.Descriptor(
@@ -1187,8 +1283,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3619,
-  serialized_end=3691,
+  serialized_start=4091,
+  serialized_end=4163,
 )
 
 _HARDWAREFEATURES_FIRMWARECONFIGURATION = _descriptor.Descriptor(
@@ -1225,8 +1321,67 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3693,
-  serialized_end=3745,
+  serialized_start=4165,
+  serialized_end=4217,
+)
+
+_HARDWAREFEATURES_AUDIO_CARDCONFIG = _descriptor.Descriptor(
+  name='CardConfig',
+  full_name='chromiumos.config.api.HardwareFeatures.Audio.CardConfig',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='card_name', full_name='chromiumos.config.api.HardwareFeatures.Audio.CardConfig.card_name', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='ucm_suffix', full_name='chromiumos.config.api.HardwareFeatures.Audio.CardConfig.ucm_suffix', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='ucm_config', full_name='chromiumos.config.api.HardwareFeatures.Audio.CardConfig.ucm_config', index=2,
+      number=3, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='cras_config', full_name='chromiumos.config.api.HardwareFeatures.Audio.CardConfig.cras_config', index=3,
+      number=4, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='sound_card_init_config', full_name='chromiumos.config.api.HardwareFeatures.Audio.CardConfig.sound_card_init_config', index=4,
+      number=5, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=4853,
+  serialized_end=5211,
 )
 
 _HARDWAREFEATURES_AUDIO = _descriptor.Descriptor(
@@ -1279,13 +1434,28 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='card_configs', full_name='chromiumos.config.api.HardwareFeatures.Audio.card_configs', index=6,
+      number=7, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='cras_config', full_name='chromiumos.config.api.HardwareFeatures.Audio.cras_config', index=7,
+      number=8, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
-  nested_types=[],
+  nested_types=[_HARDWAREFEATURES_AUDIO_CARDCONFIG, ],
   enum_types=[
     _HARDWAREFEATURES_AUDIO_AUDIOCODEC,
     _HARDWAREFEATURES_AUDIO_AMPLIFIER,
+    _HARDWAREFEATURES_AUDIO_AUDIOCONFIGSTRUCTURE,
   ],
   serialized_options=None,
   is_extendable=False,
@@ -1293,8 +1463,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3748,
-  serialized_end=4525,
+  serialized_start=4220,
+  serialized_end=5608,
 )
 
 _HARDWAREFEATURES_CAMERA_DEVICE = _descriptor.Descriptor(
@@ -1359,8 +1529,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4611,
-  serialized_end=4949,
+  serialized_start=5694,
+  serialized_end=6032,
 )
 
 _HARDWAREFEATURES_CAMERA = _descriptor.Descriptor(
@@ -1394,8 +1564,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4528,
-  serialized_end=5289,
+  serialized_start=5611,
+  serialized_end=6372,
 )
 
 _HARDWAREFEATURES_ACCELEROMETER = _descriptor.Descriptor(
@@ -1432,8 +1602,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5292,
-  serialized_end=5460,
+  serialized_start=6375,
+  serialized_end=6543,
 )
 
 _HARDWAREFEATURES_GYROSCOPE = _descriptor.Descriptor(
@@ -1470,8 +1640,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5463,
-  serialized_end=5619,
+  serialized_start=6546,
+  serialized_end=6702,
 )
 
 _HARDWAREFEATURES_MAGNETOMETER = _descriptor.Descriptor(
@@ -1508,8 +1678,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5622,
-  serialized_end=5787,
+  serialized_start=6705,
+  serialized_end=6870,
 )
 
 _HARDWAREFEATURES_LIGHTSENSOR = _descriptor.Descriptor(
@@ -1546,8 +1716,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5790,
-  serialized_end=5952,
+  serialized_start=6873,
+  serialized_end=7035,
 )
 
 _HARDWAREFEATURES_SCREEN = _descriptor.Descriptor(
@@ -1584,8 +1754,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5955,
-  serialized_end=6125,
+  serialized_start=7038,
+  serialized_end=7208,
 )
 
 _HARDWAREFEATURES_FORMFACTOR = _descriptor.Descriptor(
@@ -1616,8 +1786,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=6128,
-  serialized_end=6383,
+  serialized_start=7211,
+  serialized_end=7466,
 )
 
 _HARDWAREFEATURES_STYLUS = _descriptor.Descriptor(
@@ -1648,8 +1818,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=6386,
-  serialized_end=6541,
+  serialized_start=7469,
+  serialized_end=7624,
 )
 
 _HARDWAREFEATURES_KEYBOARD = _descriptor.Descriptor(
@@ -1688,6 +1858,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='backlight_user_steps', full_name='chromiumos.config.api.HardwareFeatures.Keyboard.backlight_user_steps', index=4,
+      number=5, type=1, cpp_type=5, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -1701,8 +1878,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=6544,
-  serialized_end=6932,
+  serialized_start=7627,
+  serialized_end=8045,
 )
 
 _HARDWAREFEATURES_MEMORY = _descriptor.Descriptor(
@@ -1732,8 +1909,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=6934,
-  serialized_end=7008,
+  serialized_start=8047,
+  serialized_end=8121,
 )
 
 _HARDWAREFEATURES_FINGERPRINT = _descriptor.Descriptor(
@@ -1778,8 +1955,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=7011,
-  serialized_end=7339,
+  serialized_start=8124,
+  serialized_end=8452,
 )
 
 _HARDWAREFEATURES_STORAGE = _descriptor.Descriptor(
@@ -1816,8 +1993,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=7341,
-  serialized_end=7443,
+  serialized_start=8454,
+  serialized_end=8556,
 )
 
 _HARDWAREFEATURES_BLUETOOTH = _descriptor.Descriptor(
@@ -1854,8 +2031,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=7446,
-  serialized_end=7586,
+  serialized_start=8559,
+  serialized_end=8699,
 )
 
 _HARDWAREFEATURES_BARRELJACK = _descriptor.Descriptor(
@@ -1885,8 +2062,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=7588,
-  serialized_end=7666,
+  serialized_start=8701,
+  serialized_end=8779,
 )
 
 _HARDWAREFEATURES_WIFI = _descriptor.Descriptor(
@@ -1924,8 +2101,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=7669,
-  serialized_end=7916,
+  serialized_start=8782,
+  serialized_end=9029,
 )
 
 _HARDWAREFEATURES_BUTTON = _descriptor.Descriptor(
@@ -1971,8 +2148,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=7919,
-  serialized_end=8207,
+  serialized_start=9032,
+  serialized_end=9320,
 )
 
 _HARDWAREFEATURES_EMBEDDEDCONTROLLER = _descriptor.Descriptor(
@@ -2004,6 +2181,20 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='feature_typec_cmd', full_name='chromiumos.config.api.HardwareFeatures.EmbeddedController.feature_typec_cmd', index=3,
+      number=4, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='cbi', full_name='chromiumos.config.api.HardwareFeatures.EmbeddedController.cbi', index=4,
+      number=5, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -2017,8 +2208,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=8210,
-  serialized_end=8539,
+  serialized_start=9323,
+  serialized_end=9790,
 )
 
 _HARDWAREFEATURES_TRUSTEDPLATFORMMODULE = _descriptor.Descriptor(
@@ -2049,8 +2240,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=8542,
-  serialized_end=8766,
+  serialized_start=9793,
+  serialized_end=10017,
 )
 
 _HARDWAREFEATURES_HOTWORDING = _descriptor.Descriptor(
@@ -2080,8 +2271,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=8768,
-  serialized_end=8846,
+  serialized_start=10019,
+  serialized_end=10097,
 )
 
 _HARDWAREFEATURES_DISPLAY = _descriptor.Descriptor(
@@ -2112,8 +2303,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=8849,
-  serialized_end=9018,
+  serialized_start=10100,
+  serialized_end=10269,
 )
 
 _HARDWAREFEATURES_TOUCHPAD = _descriptor.Descriptor(
@@ -2143,8 +2334,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9020,
-  serialized_end=9096,
+  serialized_start=10271,
+  serialized_end=10347,
 )
 
 _HARDWAREFEATURES_MICROPHONEMUTESWITCH = _descriptor.Descriptor(
@@ -2174,8 +2365,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9098,
-  serialized_end=9186,
+  serialized_start=10349,
+  serialized_end=10437,
 )
 
 _HARDWAREFEATURES_BATTERY_LIFETIME = _descriptor.Descriptor(
@@ -2233,8 +2424,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9419,
-  serialized_end=9706,
+  serialized_start=10670,
+  serialized_end=10957,
 )
 
 _HARDWAREFEATURES_BATTERY_CHARGING = _descriptor.Descriptor(
@@ -2278,8 +2469,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9709,
-  serialized_end=9883,
+  serialized_start=10960,
+  serialized_end=11134,
 )
 
 _HARDWAREFEATURES_BATTERY = _descriptor.Descriptor(
@@ -2323,8 +2514,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9189,
-  serialized_end=9883,
+  serialized_start=10440,
+  serialized_end=11134,
 )
 
 _HARDWAREFEATURES_PRIVACYSCREEN = _descriptor.Descriptor(
@@ -2354,8 +2545,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9885,
-  serialized_end=9966,
+  serialized_start=11136,
+  serialized_end=11217,
 )
 
 _HARDWAREFEATURES_SOC = _descriptor.Descriptor(
@@ -2385,8 +2576,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9968,
-  serialized_end=10037,
+  serialized_start=11219,
+  serialized_end=11288,
 )
 
 _HARDWAREFEATURES_DISPLAYPORTCONVERTER = _descriptor.Descriptor(
@@ -2416,8 +2607,108 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=10039,
-  serialized_end=10136,
+  serialized_start=11290,
+  serialized_end=11387,
+)
+
+_HARDWAREFEATURES_HPS = _descriptor.Descriptor(
+  name='Hps',
+  full_name='chromiumos.config.api.HardwareFeatures.Hps',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='present', full_name='chromiumos.config.api.HardwareFeatures.Hps.present', index=0,
+      number=1, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=11389,
+  serialized_end=11460,
+)
+
+_HARDWAREFEATURES_POE = _descriptor.Descriptor(
+  name='PoE',
+  full_name='chromiumos.config.api.HardwareFeatures.PoE',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='present', full_name='chromiumos.config.api.HardwareFeatures.PoE.present', index=0,
+      number=1, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=11462,
+  serialized_end=11533,
+)
+
+_HARDWAREFEATURES_POWERSUPPLY = _descriptor.Descriptor(
+  name='PowerSupply',
+  full_name='chromiumos.config.api.HardwareFeatures.PowerSupply',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='barreljack', full_name='chromiumos.config.api.HardwareFeatures.PowerSupply.barreljack', index=0,
+      number=1, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='usb_min_ac_watts', full_name='chromiumos.config.api.HardwareFeatures.PowerSupply.usb_min_ac_watts', index=1,
+      number=2, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=11535,
+  serialized_end=11643,
 )
 
 _HARDWAREFEATURES = _descriptor.Descriptor(
@@ -2443,7 +2734,7 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='lte', full_name='chromiumos.config.api.HardwareFeatures.lte', index=2,
+      name='cellular', full_name='chromiumos.config.api.HardwareFeatures.cellular', index=2,
       number=3, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
@@ -2659,10 +2950,31 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='hps', full_name='chromiumos.config.api.HardwareFeatures.hps', index=33,
+      number=34, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='poe', full_name='chromiumos.config.api.HardwareFeatures.poe', index=34,
+      number=35, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='power_supply', full_name='chromiumos.config.api.HardwareFeatures.power_supply', index=35,
+      number=36, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
-  nested_types=[_HARDWAREFEATURES_COUNT, _HARDWAREFEATURES_USBC, _HARDWAREFEATURES_USBA, _HARDWAREFEATURES_LTE, _HARDWAREFEATURES_HDMI, _HARDWAREFEATURES_FIRMWARECONFIGURATION, _HARDWAREFEATURES_AUDIO, _HARDWAREFEATURES_CAMERA, _HARDWAREFEATURES_ACCELEROMETER, _HARDWAREFEATURES_GYROSCOPE, _HARDWAREFEATURES_MAGNETOMETER, _HARDWAREFEATURES_LIGHTSENSOR, _HARDWAREFEATURES_SCREEN, _HARDWAREFEATURES_FORMFACTOR, _HARDWAREFEATURES_STYLUS, _HARDWAREFEATURES_KEYBOARD, _HARDWAREFEATURES_MEMORY, _HARDWAREFEATURES_FINGERPRINT, _HARDWAREFEATURES_STORAGE, _HARDWAREFEATURES_BLUETOOTH, _HARDWAREFEATURES_BARRELJACK, _HARDWAREFEATURES_WIFI, _HARDWAREFEATURES_BUTTON, _HARDWAREFEATURES_EMBEDDEDCONTROLLER, _HARDWAREFEATURES_TRUSTEDPLATFORMMODULE, _HARDWAREFEATURES_HOTWORDING, _HARDWAREFEATURES_DISPLAY, _HARDWAREFEATURES_TOUCHPAD, _HARDWAREFEATURES_MICROPHONEMUTESWITCH, _HARDWAREFEATURES_BATTERY, _HARDWAREFEATURES_PRIVACYSCREEN, _HARDWAREFEATURES_SOC, _HARDWAREFEATURES_DISPLAYPORTCONVERTER, ],
+  nested_types=[_HARDWAREFEATURES_COUNT, _HARDWAREFEATURES_USBC, _HARDWAREFEATURES_USBA, _HARDWAREFEATURES_CELLULAR, _HARDWAREFEATURES_HDMI, _HARDWAREFEATURES_FIRMWARECONFIGURATION, _HARDWAREFEATURES_AUDIO, _HARDWAREFEATURES_CAMERA, _HARDWAREFEATURES_ACCELEROMETER, _HARDWAREFEATURES_GYROSCOPE, _HARDWAREFEATURES_MAGNETOMETER, _HARDWAREFEATURES_LIGHTSENSOR, _HARDWAREFEATURES_SCREEN, _HARDWAREFEATURES_FORMFACTOR, _HARDWAREFEATURES_STYLUS, _HARDWAREFEATURES_KEYBOARD, _HARDWAREFEATURES_MEMORY, _HARDWAREFEATURES_FINGERPRINT, _HARDWAREFEATURES_STORAGE, _HARDWAREFEATURES_BLUETOOTH, _HARDWAREFEATURES_BARRELJACK, _HARDWAREFEATURES_WIFI, _HARDWAREFEATURES_BUTTON, _HARDWAREFEATURES_EMBEDDEDCONTROLLER, _HARDWAREFEATURES_TRUSTEDPLATFORMMODULE, _HARDWAREFEATURES_HOTWORDING, _HARDWAREFEATURES_DISPLAY, _HARDWAREFEATURES_TOUCHPAD, _HARDWAREFEATURES_MICROPHONEMUTESWITCH, _HARDWAREFEATURES_BATTERY, _HARDWAREFEATURES_PRIVACYSCREEN, _HARDWAREFEATURES_SOC, _HARDWAREFEATURES_DISPLAYPORTCONVERTER, _HARDWAREFEATURES_HPS, _HARDWAREFEATURES_POE, _HARDWAREFEATURES_POWERSUPPLY, ],
   enum_types=[
     _HARDWAREFEATURES_PRESENT,
   ],
@@ -2672,8 +2984,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1012,
-  serialized_end=10198,
+  serialized_start=1103,
+  serialized_end=11705,
 )
 
 _TOPOLOGY_DESCRIPTIONENTRY.containing_type = _TOPOLOGY
@@ -2688,20 +3000,30 @@
 _HARDWAREFEATURES_USBC.containing_type = _HARDWAREFEATURES
 _HARDWAREFEATURES_USBA.fields_by_name['count'].message_type = _HARDWAREFEATURES_COUNT
 _HARDWAREFEATURES_USBA.containing_type = _HARDWAREFEATURES
-_HARDWAREFEATURES_LTE.fields_by_name['present'].enum_type = _HARDWAREFEATURES_PRESENT
-_HARDWAREFEATURES_LTE.containing_type = _HARDWAREFEATURES
+_HARDWAREFEATURES_CELLULAR.fields_by_name['present'].enum_type = _HARDWAREFEATURES_PRESENT
+_HARDWAREFEATURES_CELLULAR.fields_by_name['type'].enum_type = _HARDWAREFEATURES_CELLULAR_CELLULARTYPE
+_HARDWAREFEATURES_CELLULAR.containing_type = _HARDWAREFEATURES
+_HARDWAREFEATURES_CELLULAR_CELLULARTYPE.containing_type = _HARDWAREFEATURES_CELLULAR
 _HARDWAREFEATURES_HDMI.fields_by_name['present'].enum_type = _HARDWAREFEATURES_PRESENT
 _HARDWAREFEATURES_HDMI.containing_type = _HARDWAREFEATURES
 _HARDWAREFEATURES_FIRMWARECONFIGURATION.containing_type = _HARDWAREFEATURES
+_HARDWAREFEATURES_AUDIO_CARDCONFIG.fields_by_name['ucm_suffix'].message_type = google_dot_protobuf_dot_wrappers__pb2._STRINGVALUE
+_HARDWAREFEATURES_AUDIO_CARDCONFIG.fields_by_name['ucm_config'].enum_type = _HARDWAREFEATURES_AUDIO_AUDIOCONFIGSTRUCTURE
+_HARDWAREFEATURES_AUDIO_CARDCONFIG.fields_by_name['cras_config'].enum_type = _HARDWAREFEATURES_AUDIO_AUDIOCONFIGSTRUCTURE
+_HARDWAREFEATURES_AUDIO_CARDCONFIG.fields_by_name['sound_card_init_config'].enum_type = _HARDWAREFEATURES_AUDIO_AUDIOCONFIGSTRUCTURE
+_HARDWAREFEATURES_AUDIO_CARDCONFIG.containing_type = _HARDWAREFEATURES_AUDIO
 _HARDWAREFEATURES_AUDIO.fields_by_name['audio_codec'].enum_type = _HARDWAREFEATURES_AUDIO_AUDIOCODEC
 _HARDWAREFEATURES_AUDIO.fields_by_name['speaker_amp'].enum_type = _HARDWAREFEATURES_AUDIO_AMPLIFIER
 _HARDWAREFEATURES_AUDIO.fields_by_name['headphone_codec'].enum_type = _HARDWAREFEATURES_AUDIO_AUDIOCODEC
 _HARDWAREFEATURES_AUDIO.fields_by_name['lid_microphone'].message_type = _HARDWAREFEATURES_COUNT
 _HARDWAREFEATURES_AUDIO.fields_by_name['base_microphone'].message_type = _HARDWAREFEATURES_COUNT
 _HARDWAREFEATURES_AUDIO.fields_by_name['speaker_amplifier'].message_type = chromiumos_dot_config_dot_api_dot_component__pb2._COMPONENT_AMPLIFIER
+_HARDWAREFEATURES_AUDIO.fields_by_name['card_configs'].message_type = _HARDWAREFEATURES_AUDIO_CARDCONFIG
+_HARDWAREFEATURES_AUDIO.fields_by_name['cras_config'].enum_type = _HARDWAREFEATURES_AUDIO_AUDIOCONFIGSTRUCTURE
 _HARDWAREFEATURES_AUDIO.containing_type = _HARDWAREFEATURES
 _HARDWAREFEATURES_AUDIO_AUDIOCODEC.containing_type = _HARDWAREFEATURES_AUDIO
 _HARDWAREFEATURES_AUDIO_AMPLIFIER.containing_type = _HARDWAREFEATURES_AUDIO
+_HARDWAREFEATURES_AUDIO_AUDIOCONFIGSTRUCTURE.containing_type = _HARDWAREFEATURES_AUDIO
 _HARDWAREFEATURES_CAMERA_DEVICE.fields_by_name['interface'].enum_type = _HARDWAREFEATURES_CAMERA_INTERFACE
 _HARDWAREFEATURES_CAMERA_DEVICE.fields_by_name['facing'].enum_type = _HARDWAREFEATURES_CAMERA_FACING
 _HARDWAREFEATURES_CAMERA_DEVICE.fields_by_name['orientation'].enum_type = _HARDWAREFEATURES_CAMERA_ORIENTATION
@@ -2764,6 +3086,8 @@
 _HARDWAREFEATURES_EMBEDDEDCONTROLLER.fields_by_name['present'].enum_type = _HARDWAREFEATURES_PRESENT
 _HARDWAREFEATURES_EMBEDDEDCONTROLLER.fields_by_name['ec_type'].enum_type = _HARDWAREFEATURES_EMBEDDEDCONTROLLER_EMBEDDEDCONTROLLERTYPE
 _HARDWAREFEATURES_EMBEDDEDCONTROLLER.fields_by_name['part'].message_type = chromiumos_dot_config_dot_api_dot_component__pb2._COMPONENT_EMBEDDEDCONTROLLER
+_HARDWAREFEATURES_EMBEDDEDCONTROLLER.fields_by_name['feature_typec_cmd'].enum_type = _HARDWAREFEATURES_PRESENT
+_HARDWAREFEATURES_EMBEDDEDCONTROLLER.fields_by_name['cbi'].enum_type = _HARDWAREFEATURES_PRESENT
 _HARDWAREFEATURES_EMBEDDEDCONTROLLER.containing_type = _HARDWAREFEATURES
 _HARDWAREFEATURES_EMBEDDEDCONTROLLER_EMBEDDEDCONTROLLERTYPE.containing_type = _HARDWAREFEATURES_EMBEDDEDCONTROLLER
 _HARDWAREFEATURES_TRUSTEDPLATFORMMODULE.fields_by_name['tpm_type'].enum_type = _HARDWAREFEATURES_TRUSTEDPLATFORMMODULE_TRUSTEDPLATFORMMODULETYPE
@@ -2798,9 +3122,15 @@
 _HARDWAREFEATURES_SOC.containing_type = _HARDWAREFEATURES
 _HARDWAREFEATURES_DISPLAYPORTCONVERTER.fields_by_name['converters'].message_type = chromiumos_dot_config_dot_api_dot_component__pb2._COMPONENT_DISPLAYPORTCONVERTER
 _HARDWAREFEATURES_DISPLAYPORTCONVERTER.containing_type = _HARDWAREFEATURES
+_HARDWAREFEATURES_HPS.fields_by_name['present'].enum_type = _HARDWAREFEATURES_PRESENT
+_HARDWAREFEATURES_HPS.containing_type = _HARDWAREFEATURES
+_HARDWAREFEATURES_POE.fields_by_name['present'].enum_type = _HARDWAREFEATURES_PRESENT
+_HARDWAREFEATURES_POE.containing_type = _HARDWAREFEATURES
+_HARDWAREFEATURES_POWERSUPPLY.fields_by_name['barreljack'].enum_type = _HARDWAREFEATURES_PRESENT
+_HARDWAREFEATURES_POWERSUPPLY.containing_type = _HARDWAREFEATURES
 _HARDWAREFEATURES.fields_by_name['usb_c'].message_type = _HARDWAREFEATURES_USBC
 _HARDWAREFEATURES.fields_by_name['usb_a'].message_type = _HARDWAREFEATURES_USBA
-_HARDWAREFEATURES.fields_by_name['lte'].message_type = _HARDWAREFEATURES_LTE
+_HARDWAREFEATURES.fields_by_name['cellular'].message_type = _HARDWAREFEATURES_CELLULAR
 _HARDWAREFEATURES.fields_by_name['hdmi'].message_type = _HARDWAREFEATURES_HDMI
 _HARDWAREFEATURES.fields_by_name['fw_config'].message_type = _HARDWAREFEATURES_FIRMWARECONFIGURATION
 _HARDWAREFEATURES.fields_by_name['audio'].message_type = _HARDWAREFEATURES_AUDIO
@@ -2831,6 +3161,9 @@
 _HARDWAREFEATURES.fields_by_name['privacy_screen'].message_type = _HARDWAREFEATURES_PRIVACYSCREEN
 _HARDWAREFEATURES.fields_by_name['soc'].message_type = _HARDWAREFEATURES_SOC
 _HARDWAREFEATURES.fields_by_name['dp_converter'].message_type = _HARDWAREFEATURES_DISPLAYPORTCONVERTER
+_HARDWAREFEATURES.fields_by_name['hps'].message_type = _HARDWAREFEATURES_HPS
+_HARDWAREFEATURES.fields_by_name['poe'].message_type = _HARDWAREFEATURES_POE
+_HARDWAREFEATURES.fields_by_name['power_supply'].message_type = _HARDWAREFEATURES_POWERSUPPLY
 _HARDWAREFEATURES_PRESENT.containing_type = _HARDWAREFEATURES
 DESCRIPTOR.message_types_by_name['Topology'] = _TOPOLOGY
 DESCRIPTOR.message_types_by_name['Duration'] = _DURATION
@@ -2882,10 +3215,10 @@
     })
   ,
 
-  'Lte' : _reflection.GeneratedProtocolMessageType('Lte', (_message.Message,), {
-    'DESCRIPTOR' : _HARDWAREFEATURES_LTE,
+  'Cellular' : _reflection.GeneratedProtocolMessageType('Cellular', (_message.Message,), {
+    'DESCRIPTOR' : _HARDWAREFEATURES_CELLULAR,
     '__module__' : 'chromiumos.config.api.topology_pb2'
-    # @@protoc_insertion_point(class_scope:chromiumos.config.api.HardwareFeatures.Lte)
+    # @@protoc_insertion_point(class_scope:chromiumos.config.api.HardwareFeatures.Cellular)
     })
   ,
 
@@ -2904,6 +3237,13 @@
   ,
 
   'Audio' : _reflection.GeneratedProtocolMessageType('Audio', (_message.Message,), {
+
+    'CardConfig' : _reflection.GeneratedProtocolMessageType('CardConfig', (_message.Message,), {
+      'DESCRIPTOR' : _HARDWAREFEATURES_AUDIO_CARDCONFIG,
+      '__module__' : 'chromiumos.config.api.topology_pb2'
+      # @@protoc_insertion_point(class_scope:chromiumos.config.api.HardwareFeatures.Audio.CardConfig)
+      })
+    ,
     'DESCRIPTOR' : _HARDWAREFEATURES_AUDIO,
     '__module__' : 'chromiumos.config.api.topology_pb2'
     # @@protoc_insertion_point(class_scope:chromiumos.config.api.HardwareFeatures.Audio)
@@ -3112,6 +3452,27 @@
     # @@protoc_insertion_point(class_scope:chromiumos.config.api.HardwareFeatures.DisplayPortConverter)
     })
   ,
+
+  'Hps' : _reflection.GeneratedProtocolMessageType('Hps', (_message.Message,), {
+    'DESCRIPTOR' : _HARDWAREFEATURES_HPS,
+    '__module__' : 'chromiumos.config.api.topology_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.config.api.HardwareFeatures.Hps)
+    })
+  ,
+
+  'PoE' : _reflection.GeneratedProtocolMessageType('PoE', (_message.Message,), {
+    'DESCRIPTOR' : _HARDWAREFEATURES_POE,
+    '__module__' : 'chromiumos.config.api.topology_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.config.api.HardwareFeatures.PoE)
+    })
+  ,
+
+  'PowerSupply' : _reflection.GeneratedProtocolMessageType('PowerSupply', (_message.Message,), {
+    'DESCRIPTOR' : _HARDWAREFEATURES_POWERSUPPLY,
+    '__module__' : 'chromiumos.config.api.topology_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.config.api.HardwareFeatures.PowerSupply)
+    })
+  ,
   'DESCRIPTOR' : _HARDWAREFEATURES,
   '__module__' : 'chromiumos.config.api.topology_pb2'
   # @@protoc_insertion_point(class_scope:chromiumos.config.api.HardwareFeatures)
@@ -3120,10 +3481,11 @@
 _sym_db.RegisterMessage(HardwareFeatures.Count)
 _sym_db.RegisterMessage(HardwareFeatures.UsbC)
 _sym_db.RegisterMessage(HardwareFeatures.UsbA)
-_sym_db.RegisterMessage(HardwareFeatures.Lte)
+_sym_db.RegisterMessage(HardwareFeatures.Cellular)
 _sym_db.RegisterMessage(HardwareFeatures.Hdmi)
 _sym_db.RegisterMessage(HardwareFeatures.FirmwareConfiguration)
 _sym_db.RegisterMessage(HardwareFeatures.Audio)
+_sym_db.RegisterMessage(HardwareFeatures.Audio.CardConfig)
 _sym_db.RegisterMessage(HardwareFeatures.Camera)
 _sym_db.RegisterMessage(HardwareFeatures.Camera.Device)
 _sym_db.RegisterMessage(HardwareFeatures.Accelerometer)
@@ -3153,6 +3515,9 @@
 _sym_db.RegisterMessage(HardwareFeatures.PrivacyScreen)
 _sym_db.RegisterMessage(HardwareFeatures.Soc)
 _sym_db.RegisterMessage(HardwareFeatures.DisplayPortConverter)
+_sym_db.RegisterMessage(HardwareFeatures.Hps)
+_sym_db.RegisterMessage(HardwareFeatures.PoE)
+_sym_db.RegisterMessage(HardwareFeatures.PowerSupply)
 
 
 DESCRIPTOR._options = None
diff --git a/api/gen/chromiumos/config/public_replication/testdata/public_replication_testdata_pb2.py b/api/gen/chromiumos/config/public_replication/testdata/public_replication_testdata_pb2.py
index 750ccaa..9bdd4e3 100644
--- a/api/gen/chromiumos/config/public_replication/testdata/public_replication_testdata_pb2.py
+++ b/api/gen/chromiumos/config/public_replication/testdata/public_replication_testdata_pb2.py
@@ -20,7 +20,7 @@
   syntax='proto3',
   serialized_options=b'Z@go.chromium.org/chromiumos/config/go/public_replication/testdata',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\nOchromiumos/config/public_replication/testdata/public_replication_testdata.proto\x12-chromiumos.config.public_replication.testdata\x1a=chromiumos/config/public_replication/public_replication.proto\"\x9b\x02\n\x19PublicReplicationTestdata\x12S\n\x12public_replication\x18\x01 \x01(\x0b\x32\x37.chromiumos.config.public_replication.PublicReplication\x12\x0c\n\x04str1\x18\x02 \x01(\t\x12\x0c\n\x04str2\x18\x03 \x01(\t\x12`\n\x04map1\x18\x04 \x03(\x0b\x32R.chromiumos.config.public_replication.testdata.PublicReplicationTestdata.Map1Entry\x1a+\n\tMap1Entry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\"\xe5\x01\n\x10WrapperTestdata1\x12\n\n\x02n1\x18\x01 \x01(\x05\x12]\n\x0bpr_testdata\x18\x02 \x01(\x0b\x32H.chromiumos.config.public_replication.testdata.PublicReplicationTestdata\x12\x66\n\x14repeated_pr_testdata\x18\x03 \x03(\x0b\x32H.chromiumos.config.public_replication.testdata.PublicReplicationTestdata\"n\n\x10WrapperTestdata2\x12Z\n\x11wrapper_testdata1\x18\x01 \x01(\x0b\x32?.chromiumos.config.public_replication.testdata.WrapperTestdata1\"\xd2\x01\n\x10WrapperTestdata3\x12S\n\x12public_replication\x18\x01 \x01(\x0b\x32\x37.chromiumos.config.public_replication.PublicReplication\x12\n\n\x02\x62\x31\x18\x02 \x01(\x08\x12]\n\x0bpr_testdata\x18\x03 \x01(\x0b\x32H.chromiumos.config.public_replication.testdata.PublicReplicationTestdata\"z\n\x10RecursiveMessage\x12\n\n\x02\x62\x31\x18\x01 \x01(\x08\x12Z\n\x11recursive_message\x18\x02 \x01(\x0b\x32?.chromiumos.config.public_replication.testdata.RecursiveMessageBBZ@go.chromium.org/chromiumos/config/go/public_replication/testdatab\x06proto3'
+  serialized_pb=b'\nOchromiumos/config/public_replication/testdata/public_replication_testdata.proto\x12-chromiumos.config.public_replication.testdata\x1a=chromiumos/config/public_replication/public_replication.proto\"\x9b\x02\n\x19PublicReplicationTestdata\x12S\n\x12public_replication\x18\x01 \x01(\x0b\x32\x37.chromiumos.config.public_replication.PublicReplication\x12\x0c\n\x04str1\x18\x02 \x01(\t\x12\x0c\n\x04str2\x18\x03 \x01(\t\x12`\n\x04map1\x18\x04 \x03(\x0b\x32R.chromiumos.config.public_replication.testdata.PublicReplicationTestdata.Map1Entry\x1a+\n\tMap1Entry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\"\xe5\x01\n\x10WrapperTestdata1\x12\n\n\x02n1\x18\x01 \x01(\x05\x12]\n\x0bpr_testdata\x18\x02 \x01(\x0b\x32H.chromiumos.config.public_replication.testdata.PublicReplicationTestdata\x12\x66\n\x14repeated_pr_testdata\x18\x03 \x03(\x0b\x32H.chromiumos.config.public_replication.testdata.PublicReplicationTestdata\"n\n\x10WrapperTestdata2\x12Z\n\x11wrapper_testdata1\x18\x01 \x01(\x0b\x32?.chromiumos.config.public_replication.testdata.WrapperTestdata1\"\xd2\x01\n\x10WrapperTestdata3\x12S\n\x12public_replication\x18\x01 \x01(\x0b\x32\x37.chromiumos.config.public_replication.PublicReplication\x12\n\n\x02\x62\x31\x18\x02 \x01(\x08\x12]\n\x0bpr_testdata\x18\x03 \x01(\x0b\x32H.chromiumos.config.public_replication.testdata.PublicReplicationTestdata\"z\n\x10RecursiveMessage\x12\n\n\x02\x62\x31\x18\x01 \x01(\x08\x12Z\n\x11recursive_message\x18\x02 \x01(\x0b\x32?.chromiumos.config.public_replication.testdata.RecursiveMessage\"\xe3\x01\n\x0ePrivateMessage\x12T\n\x06\x63onfig\x18\x01 \x01(\x0b\x32\x44.chromiumos.config.public_replication.testdata.PrivateMessage.Config\x1a{\n\x06\x43onfig\x12Z\n\x07payload\x18\x01 \x03(\x0b\x32I.chromiumos.config.public_replication.testdata.PrivateMessage.Config.Test\x1a\x15\n\x04Test\x12\r\n\x05\x62ools\x18\x01 \x01(\x08\"n\n\x14NestedPrivateMessage\x12V\n\x0fnested_messages\x18\x01 \x01(\x0b\x32=.chromiumos.config.public_replication.testdata.PrivateMessage\"v\n\x1cNestedRepeatedPrivateMessage\x12V\n\x0fnested_messages\x18\x01 \x03(\x0b\x32=.chromiumos.config.public_replication.testdata.PrivateMessageBBZ@go.chromium.org/chromiumos/config/go/public_replication/testdatab\x06proto3'
   ,
   dependencies=[chromiumos_dot_config_dot_public__replication_dot_public__replication__pb2.DESCRIPTOR,])
 
@@ -280,6 +280,164 @@
   serialized_end=1158,
 )
 
+
+_PRIVATEMESSAGE_CONFIG_TEST = _descriptor.Descriptor(
+  name='Test',
+  full_name='chromiumos.config.public_replication.testdata.PrivateMessage.Config.Test',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='bools', full_name='chromiumos.config.public_replication.testdata.PrivateMessage.Config.Test.bools', index=0,
+      number=1, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1367,
+  serialized_end=1388,
+)
+
+_PRIVATEMESSAGE_CONFIG = _descriptor.Descriptor(
+  name='Config',
+  full_name='chromiumos.config.public_replication.testdata.PrivateMessage.Config',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='payload', full_name='chromiumos.config.public_replication.testdata.PrivateMessage.Config.payload', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[_PRIVATEMESSAGE_CONFIG_TEST, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1265,
+  serialized_end=1388,
+)
+
+_PRIVATEMESSAGE = _descriptor.Descriptor(
+  name='PrivateMessage',
+  full_name='chromiumos.config.public_replication.testdata.PrivateMessage',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='config', full_name='chromiumos.config.public_replication.testdata.PrivateMessage.config', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[_PRIVATEMESSAGE_CONFIG, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1161,
+  serialized_end=1388,
+)
+
+
+_NESTEDPRIVATEMESSAGE = _descriptor.Descriptor(
+  name='NestedPrivateMessage',
+  full_name='chromiumos.config.public_replication.testdata.NestedPrivateMessage',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='nested_messages', full_name='chromiumos.config.public_replication.testdata.NestedPrivateMessage.nested_messages', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1390,
+  serialized_end=1500,
+)
+
+
+_NESTEDREPEATEDPRIVATEMESSAGE = _descriptor.Descriptor(
+  name='NestedRepeatedPrivateMessage',
+  full_name='chromiumos.config.public_replication.testdata.NestedRepeatedPrivateMessage',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='nested_messages', full_name='chromiumos.config.public_replication.testdata.NestedRepeatedPrivateMessage.nested_messages', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1502,
+  serialized_end=1620,
+)
+
 _PUBLICREPLICATIONTESTDATA_MAP1ENTRY.containing_type = _PUBLICREPLICATIONTESTDATA
 _PUBLICREPLICATIONTESTDATA.fields_by_name['public_replication'].message_type = chromiumos_dot_config_dot_public__replication_dot_public__replication__pb2._PUBLICREPLICATION
 _PUBLICREPLICATIONTESTDATA.fields_by_name['map1'].message_type = _PUBLICREPLICATIONTESTDATA_MAP1ENTRY
@@ -289,11 +447,20 @@
 _WRAPPERTESTDATA3.fields_by_name['public_replication'].message_type = chromiumos_dot_config_dot_public__replication_dot_public__replication__pb2._PUBLICREPLICATION
 _WRAPPERTESTDATA3.fields_by_name['pr_testdata'].message_type = _PUBLICREPLICATIONTESTDATA
 _RECURSIVEMESSAGE.fields_by_name['recursive_message'].message_type = _RECURSIVEMESSAGE
+_PRIVATEMESSAGE_CONFIG_TEST.containing_type = _PRIVATEMESSAGE_CONFIG
+_PRIVATEMESSAGE_CONFIG.fields_by_name['payload'].message_type = _PRIVATEMESSAGE_CONFIG_TEST
+_PRIVATEMESSAGE_CONFIG.containing_type = _PRIVATEMESSAGE
+_PRIVATEMESSAGE.fields_by_name['config'].message_type = _PRIVATEMESSAGE_CONFIG
+_NESTEDPRIVATEMESSAGE.fields_by_name['nested_messages'].message_type = _PRIVATEMESSAGE
+_NESTEDREPEATEDPRIVATEMESSAGE.fields_by_name['nested_messages'].message_type = _PRIVATEMESSAGE
 DESCRIPTOR.message_types_by_name['PublicReplicationTestdata'] = _PUBLICREPLICATIONTESTDATA
 DESCRIPTOR.message_types_by_name['WrapperTestdata1'] = _WRAPPERTESTDATA1
 DESCRIPTOR.message_types_by_name['WrapperTestdata2'] = _WRAPPERTESTDATA2
 DESCRIPTOR.message_types_by_name['WrapperTestdata3'] = _WRAPPERTESTDATA3
 DESCRIPTOR.message_types_by_name['RecursiveMessage'] = _RECURSIVEMESSAGE
+DESCRIPTOR.message_types_by_name['PrivateMessage'] = _PRIVATEMESSAGE
+DESCRIPTOR.message_types_by_name['NestedPrivateMessage'] = _NESTEDPRIVATEMESSAGE
+DESCRIPTOR.message_types_by_name['NestedRepeatedPrivateMessage'] = _NESTEDREPEATEDPRIVATEMESSAGE
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
 PublicReplicationTestdata = _reflection.GeneratedProtocolMessageType('PublicReplicationTestdata', (_message.Message,), {
@@ -339,6 +506,43 @@
   })
 _sym_db.RegisterMessage(RecursiveMessage)
 
+PrivateMessage = _reflection.GeneratedProtocolMessageType('PrivateMessage', (_message.Message,), {
+
+  'Config' : _reflection.GeneratedProtocolMessageType('Config', (_message.Message,), {
+
+    'Test' : _reflection.GeneratedProtocolMessageType('Test', (_message.Message,), {
+      'DESCRIPTOR' : _PRIVATEMESSAGE_CONFIG_TEST,
+      '__module__' : 'chromiumos.config.public_replication.testdata.public_replication_testdata_pb2'
+      # @@protoc_insertion_point(class_scope:chromiumos.config.public_replication.testdata.PrivateMessage.Config.Test)
+      })
+    ,
+    'DESCRIPTOR' : _PRIVATEMESSAGE_CONFIG,
+    '__module__' : 'chromiumos.config.public_replication.testdata.public_replication_testdata_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.config.public_replication.testdata.PrivateMessage.Config)
+    })
+  ,
+  'DESCRIPTOR' : _PRIVATEMESSAGE,
+  '__module__' : 'chromiumos.config.public_replication.testdata.public_replication_testdata_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.config.public_replication.testdata.PrivateMessage)
+  })
+_sym_db.RegisterMessage(PrivateMessage)
+_sym_db.RegisterMessage(PrivateMessage.Config)
+_sym_db.RegisterMessage(PrivateMessage.Config.Test)
+
+NestedPrivateMessage = _reflection.GeneratedProtocolMessageType('NestedPrivateMessage', (_message.Message,), {
+  'DESCRIPTOR' : _NESTEDPRIVATEMESSAGE,
+  '__module__' : 'chromiumos.config.public_replication.testdata.public_replication_testdata_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.config.public_replication.testdata.NestedPrivateMessage)
+  })
+_sym_db.RegisterMessage(NestedPrivateMessage)
+
+NestedRepeatedPrivateMessage = _reflection.GeneratedProtocolMessageType('NestedRepeatedPrivateMessage', (_message.Message,), {
+  'DESCRIPTOR' : _NESTEDREPEATEDPRIVATEMESSAGE,
+  '__module__' : 'chromiumos.config.public_replication.testdata.public_replication_testdata_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.config.public_replication.testdata.NestedRepeatedPrivateMessage)
+  })
+_sym_db.RegisterMessage(NestedRepeatedPrivateMessage)
+
 
 DESCRIPTOR._options = None
 _PUBLICREPLICATIONTESTDATA_MAP1ENTRY._options = None
diff --git a/api/gen/chromiumos/greenness_pb2.py b/api/gen/chromiumos/greenness_pb2.py
index 9d5933d..7c51535 100644
--- a/api/gen/chromiumos/greenness_pb2.py
+++ b/api/gen/chromiumos/greenness_pb2.py
@@ -19,11 +19,36 @@
   syntax='proto3',
   serialized_options=b'\n!com.google.chrome.crosinfra.protoZ4go.chromium.org/chromiumos/infra/proto/go/chromiumos',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n\x1a\x63hromiumos/greenness.proto\x12\nchromiumos\"\x9f\x01\n\x12\x41ggregateGreenness\x12\x18\n\x10\x61ggregate_metric\x18\x01 \x01(\x03\x12\x42\n\x10target_greenness\x18\x02 \x03(\x0b\x32(.chromiumos.AggregateGreenness.Greenness\x1a+\n\tGreenness\x12\x0e\n\x06target\x18\x01 \x01(\t\x12\x0e\n\x06metric\x18\x02 \x01(\x03\x42Y\n!com.google.chrome.crosinfra.protoZ4go.chromium.org/chromiumos/infra/proto/go/chromiumosb\x06proto3'
+  serialized_pb=b'\n\x1a\x63hromiumos/greenness.proto\x12\nchromiumos\"\x8f\x02\n\x12\x41ggregateGreenness\x12\x18\n\x10\x61ggregate_metric\x18\x01 \x01(\x03\x12\x42\n\x10target_greenness\x18\x02 \x03(\x0b\x32(.chromiumos.AggregateGreenness.Greenness\x1a\x9a\x01\n\tGreenness\x12\x0e\n\x06target\x18\x01 \x01(\t\x12\x0e\n\x06metric\x18\x02 \x01(\x03\x12\x41\n\x07\x63ontext\x18\x03 \x01(\x0e\x32\x30.chromiumos.AggregateGreenness.Greenness.Context\"*\n\x07\x43ontext\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x0e\n\nIRRELEVANT\x10\x01\x42Y\n!com.google.chrome.crosinfra.protoZ4go.chromium.org/chromiumos/infra/proto/go/chromiumosb\x06proto3'
 )
 
 
 
+_AGGREGATEGREENNESS_GREENNESS_CONTEXT = _descriptor.EnumDescriptor(
+  name='Context',
+  full_name='chromiumos.AggregateGreenness.Greenness.Context',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='UNSPECIFIED', index=0, number=0,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='IRRELEVANT', index=1, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=272,
+  serialized_end=314,
+)
+_sym_db.RegisterEnumDescriptor(_AGGREGATEGREENNESS_GREENNESS_CONTEXT)
+
 
 _AGGREGATEGREENNESS_GREENNESS = _descriptor.Descriptor(
   name='Greenness',
@@ -47,11 +72,19 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='context', full_name='chromiumos.AggregateGreenness.Greenness.context', index=2,
+      number=3, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
   nested_types=[],
   enum_types=[
+    _AGGREGATEGREENNESS_GREENNESS_CONTEXT,
   ],
   serialized_options=None,
   is_extendable=False,
@@ -59,8 +92,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=159,
-  serialized_end=202,
+  serialized_start=160,
+  serialized_end=314,
 )
 
 _AGGREGATEGREENNESS = _descriptor.Descriptor(
@@ -98,10 +131,12 @@
   oneofs=[
   ],
   serialized_start=43,
-  serialized_end=202,
+  serialized_end=314,
 )
 
+_AGGREGATEGREENNESS_GREENNESS.fields_by_name['context'].enum_type = _AGGREGATEGREENNESS_GREENNESS_CONTEXT
 _AGGREGATEGREENNESS_GREENNESS.containing_type = _AGGREGATEGREENNESS
+_AGGREGATEGREENNESS_GREENNESS_CONTEXT.containing_type = _AGGREGATEGREENNESS_GREENNESS
 _AGGREGATEGREENNESS.fields_by_name['target_greenness'].message_type = _AGGREGATEGREENNESS_GREENNESS
 DESCRIPTOR.message_types_by_name['AggregateGreenness'] = _AGGREGATEGREENNESS
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
diff --git a/api/gen/chromiumos/storage_path_pb2.py b/api/gen/chromiumos/storage_path_pb2.py
index f9a0a6f..8549810 100644
--- a/api/gen/chromiumos/storage_path_pb2.py
+++ b/api/gen/chromiumos/storage_path_pb2.py
@@ -17,9 +17,9 @@
   name='chromiumos/storage_path.proto',
   package='chromiumos',
   syntax='proto3',
-  serialized_options=b'Z$go.chromium.org/chromiumos/config/go',
+  serialized_options=b'Z(go.chromium.org/chromiumos/config/go;_go',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n\x1d\x63hromiumos/storage_path.proto\x12\nchromiumos\"\x89\x01\n\x0bStoragePath\x12\x33\n\thost_type\x18\x01 \x01(\x0e\x32 .chromiumos.StoragePath.HostType\x12\x0c\n\x04path\x18\x02 \x01(\t\"7\n\x08HostType\x12\x18\n\x14HOSTTYPE_UNSPECIFIED\x10\x00\x12\t\n\x05LOCAL\x10\x01\x12\x06\n\x02GS\x10\x02\x42&Z$go.chromium.org/chromiumos/config/gob\x06proto3'
+  serialized_pb=b'\n\x1d\x63hromiumos/storage_path.proto\x12\nchromiumos\"\x89\x01\n\x0bStoragePath\x12\x33\n\thost_type\x18\x01 \x01(\x0e\x32 .chromiumos.StoragePath.HostType\x12\x0c\n\x04path\x18\x02 \x01(\t\"7\n\x08HostType\x12\x18\n\x14HOSTTYPE_UNSPECIFIED\x10\x00\x12\t\n\x05LOCAL\x10\x01\x12\x06\n\x02GS\x10\x02\x42*Z(go.chromium.org/chromiumos/config/go;_gob\x06proto3'
 )
 
 
diff --git a/api/gen/chromiumos/test/api/cros_publish_cli_pb2.py b/api/gen/chromiumos/test/api/cros_publish_cli_pb2.py
new file mode 100644
index 0000000..ed63eb2
--- /dev/null
+++ b/api/gen/chromiumos/test/api/cros_publish_cli_pb2.py
@@ -0,0 +1,132 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: chromiumos/test/api/cros_publish_cli.proto
+"""Generated protocol buffer code."""
+from chromite.third_party.google.protobuf import descriptor as _descriptor
+from chromite.third_party.google.protobuf import message as _message
+from chromite.third_party.google.protobuf import reflection as _reflection
+from chromite.third_party.google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='chromiumos/test/api/cros_publish_cli.proto',
+  package='chromiumos.test.api',
+  syntax='proto3',
+  serialized_options=b'Z-go.chromium.org/chromiumos/config/go/test/api',
+  create_key=_descriptor._internal_create_key,
+  serialized_pb=b'\n*chromiumos/test/api/cros_publish_cli.proto\x12\x13\x63hromiumos.test.api\"C\n\x12\x43rosPublishRequest\x12\x14\n\x0cgs_directory\x18\x01 \x01(\t\x12\x17\n\x0flocal_directory\x18\x02 \x01(\t\"K\n\x13\x43rosPublishResponse\x12\x0e\n\x06gs_url\x18\x01 \x01(\t\x12\r\n\x05\x65rror\x18\x02 \x01(\x08\x12\x15\n\rerror_message\x18\x03 \x01(\tB/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
+)
+
+
+
+
+_CROSPUBLISHREQUEST = _descriptor.Descriptor(
+  name='CrosPublishRequest',
+  full_name='chromiumos.test.api.CrosPublishRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='gs_directory', full_name='chromiumos.test.api.CrosPublishRequest.gs_directory', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='local_directory', full_name='chromiumos.test.api.CrosPublishRequest.local_directory', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=67,
+  serialized_end=134,
+)
+
+
+_CROSPUBLISHRESPONSE = _descriptor.Descriptor(
+  name='CrosPublishResponse',
+  full_name='chromiumos.test.api.CrosPublishResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='gs_url', full_name='chromiumos.test.api.CrosPublishResponse.gs_url', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='error', full_name='chromiumos.test.api.CrosPublishResponse.error', index=1,
+      number=2, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='error_message', full_name='chromiumos.test.api.CrosPublishResponse.error_message', index=2,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=136,
+  serialized_end=211,
+)
+
+DESCRIPTOR.message_types_by_name['CrosPublishRequest'] = _CROSPUBLISHREQUEST
+DESCRIPTOR.message_types_by_name['CrosPublishResponse'] = _CROSPUBLISHRESPONSE
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+CrosPublishRequest = _reflection.GeneratedProtocolMessageType('CrosPublishRequest', (_message.Message,), {
+  'DESCRIPTOR' : _CROSPUBLISHREQUEST,
+  '__module__' : 'chromiumos.test.api.cros_publish_cli_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.CrosPublishRequest)
+  })
+_sym_db.RegisterMessage(CrosPublishRequest)
+
+CrosPublishResponse = _reflection.GeneratedProtocolMessageType('CrosPublishResponse', (_message.Message,), {
+  'DESCRIPTOR' : _CROSPUBLISHRESPONSE,
+  '__module__' : 'chromiumos.test.api.cros_publish_cli_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.CrosPublishResponse)
+  })
+_sym_db.RegisterMessage(CrosPublishResponse)
+
+
+DESCRIPTOR._options = None
+# @@protoc_insertion_point(module_scope)
diff --git a/api/gen/chromiumos/test/api/cros_tool_runner_cli_pb2.py b/api/gen/chromiumos/test/api/cros_tool_runner_cli_pb2.py
index d408b66..4f47fed 100644
--- a/api/gen/chromiumos/test/api/cros_tool_runner_cli_pb2.py
+++ b/api/gen/chromiumos/test/api/cros_tool_runner_cli_pb2.py
@@ -25,7 +25,7 @@
   syntax='proto3',
   serialized_options=b'Z-go.chromium.org/chromiumos/config/go/test/api',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n.chromiumos/test/api/cros_tool_runner_cli.proto\x12\x13\x63hromiumos.test.api\x1a)chromiumos/test/api/provision_state.proto\x1a,chromiumos/test/api/cros_provision_cli.proto\x1a*chromiumos/test/api/test_case_result.proto\x1a$chromiumos/test/api/test_suite.proto\x1a!chromiumos/test/lab/api/dut.proto\x1a)chromiumos/test/lab/api/ip_endpoint.proto\"\xb5\x02\n\x1e\x43rosToolRunnerProvisionRequest\x12K\n\x07\x64\x65vices\x18\x01 \x03(\x0b\x32:.chromiumos.test.api.CrosToolRunnerProvisionRequest.Device\x12=\n\x10inventory_server\x18\x02 \x01(\x0b\x32#.chromiumos.test.lab.api.IpEndpoint\x12\x14\n\x0c\x61rtifact_dir\x18\x03 \x01(\t\x1aq\n\x06\x44\x65vice\x12)\n\x03\x64ut\x18\x01 \x01(\x0b\x32\x1c.chromiumos.test.lab.api.Dut\x12<\n\x0fprovision_state\x18\x02 \x01(\x0b\x32#.chromiumos.test.api.ProvisionState\"`\n\x1f\x43rosToolRunnerProvisionResponse\x12=\n\tresponses\x18\x01 \x03(\x0b\x32*.chromiumos.test.api.CrosProvisionResponse\"\x8e\x02\n\x19\x43rosToolRunnerTestRequest\x12\x33\n\x0btest_suites\x18\x01 \x03(\x0b\x32\x1e.chromiumos.test.api.TestSuite\x12\x31\n\x0bprimary_dut\x18\x02 \x01(\x0b\x32\x1c.chromiumos.test.lab.api.Dut\x12\x34\n\x0e\x63ompanion_duts\x18\x03 \x03(\x0b\x32\x1c.chromiumos.test.lab.api.Dut\x12=\n\x10inventory_server\x18\x04 \x01(\x0b\x32#.chromiumos.test.lab.api.IpEndpoint\x12\x14\n\x0c\x61rtifact_dir\x18\x05 \x01(\t\"\\\n\x1a\x43rosToolRunnerTestResponse\x12>\n\x11test_case_results\x18\x01 \x03(\x0b\x32#.chromiumos.test.api.TestCaseResult\"l\n\x1f\x43rosToolRunnerTestFinderRequest\x12\x33\n\x0btest_suites\x18\x01 \x03(\x0b\x32\x1e.chromiumos.test.api.TestSuite\x12\x14\n\x0c\x61rtifact_dir\x18\x02 \x01(\t\"W\n CrosToolRunnerTestFinderResponse\x12\x33\n\x0btest_suites\x18\x01 \x03(\x0b\x32\x1e.chromiumos.test.api.TestSuiteB/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
+  serialized_pb=b'\n.chromiumos/test/api/cros_tool_runner_cli.proto\x12\x13\x63hromiumos.test.api\x1a)chromiumos/test/api/provision_state.proto\x1a,chromiumos/test/api/cros_provision_cli.proto\x1a*chromiumos/test/api/test_case_result.proto\x1a$chromiumos/test/api/test_suite.proto\x1a!chromiumos/test/lab/api/dut.proto\x1a)chromiumos/test/lab/api/ip_endpoint.proto\"\xd6\x02\n\x1e\x43rosToolRunnerProvisionRequest\x12K\n\x07\x64\x65vices\x18\x01 \x03(\x0b\x32:.chromiumos.test.api.CrosToolRunnerProvisionRequest.Device\x12=\n\x10inventory_server\x18\x02 \x01(\x0b\x32#.chromiumos.test.lab.api.IpEndpoint\x12\x14\n\x0c\x61rtifact_dir\x18\x03 \x01(\t\x1a\x91\x01\n\x06\x44\x65vice\x12)\n\x03\x64ut\x18\x01 \x01(\x0b\x32\x1c.chromiumos.test.lab.api.Dut\x12<\n\x0fprovision_state\x18\x02 \x01(\x0b\x32#.chromiumos.test.api.ProvisionState\x12\x1e\n\x16\x63ontainer_metadata_key\x18\x03 \x01(\t\"`\n\x1f\x43rosToolRunnerProvisionResponse\x12=\n\tresponses\x18\x01 \x03(\x0b\x32*.chromiumos.test.api.CrosProvisionResponse\"\x95\x03\n\x19\x43rosToolRunnerTestRequest\x12\x33\n\x0btest_suites\x18\x01 \x03(\x0b\x32\x1e.chromiumos.test.api.TestSuite\x12J\n\x0bprimary_dut\x18\x02 \x01(\x0b\x32\x35.chromiumos.test.api.CrosToolRunnerTestRequest.Device\x12M\n\x0e\x63ompanion_duts\x18\x03 \x03(\x0b\x32\x35.chromiumos.test.api.CrosToolRunnerTestRequest.Device\x12=\n\x10inventory_server\x18\x04 \x01(\x0b\x32#.chromiumos.test.lab.api.IpEndpoint\x12\x14\n\x0c\x61rtifact_dir\x18\x05 \x01(\t\x1aS\n\x06\x44\x65vice\x12)\n\x03\x64ut\x18\x01 \x01(\x0b\x32\x1c.chromiumos.test.lab.api.Dut\x12\x1e\n\x16\x63ontainer_metadata_key\x18\x02 \x01(\t\"\\\n\x1a\x43rosToolRunnerTestResponse\x12>\n\x11test_case_results\x18\x01 \x03(\x0b\x32#.chromiumos.test.api.TestCaseResult\"\x8c\x01\n\x1f\x43rosToolRunnerTestFinderRequest\x12\x33\n\x0btest_suites\x18\x01 \x03(\x0b\x32\x1e.chromiumos.test.api.TestSuite\x12\x14\n\x0c\x61rtifact_dir\x18\x02 \x01(\t\x12\x1e\n\x16\x63ontainer_metadata_key\x18\x03 \x01(\t\"W\n CrosToolRunnerTestFinderResponse\x12\x33\n\x0btest_suites\x18\x01 \x03(\x0b\x32\x1e.chromiumos.test.api.TestSuiteB/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
   ,
   dependencies=[chromiumos_dot_test_dot_api_dot_provision__state__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_cros__provision__cli__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_test__case__result__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_test__suite__pb2.DESCRIPTOR,chromiumos_dot_test_dot_lab_dot_api_dot_dut__pb2.DESCRIPTOR,chromiumos_dot_test_dot_lab_dot_api_dot_ip__endpoint__pb2.DESCRIPTOR,])
 
@@ -54,6 +54,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='container_metadata_key', full_name='chromiumos.test.api.CrosToolRunnerProvisionRequest.Device.container_metadata_key', index=2,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -66,8 +73,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=517,
-  serialized_end=630,
+  serialized_start=518,
+  serialized_end=663,
 )
 
 _CROSTOOLRUNNERPROVISIONREQUEST = _descriptor.Descriptor(
@@ -112,7 +119,7 @@
   oneofs=[
   ],
   serialized_start=321,
-  serialized_end=630,
+  serialized_end=663,
 )
 
 
@@ -143,11 +150,49 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=632,
-  serialized_end=728,
+  serialized_start=665,
+  serialized_end=761,
 )
 
 
+_CROSTOOLRUNNERTESTREQUEST_DEVICE = _descriptor.Descriptor(
+  name='Device',
+  full_name='chromiumos.test.api.CrosToolRunnerTestRequest.Device',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='dut', full_name='chromiumos.test.api.CrosToolRunnerTestRequest.Device.dut', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='container_metadata_key', full_name='chromiumos.test.api.CrosToolRunnerTestRequest.Device.container_metadata_key', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1086,
+  serialized_end=1169,
+)
+
 _CROSTOOLRUNNERTESTREQUEST = _descriptor.Descriptor(
   name='CrosToolRunnerTestRequest',
   full_name='chromiumos.test.api.CrosToolRunnerTestRequest',
@@ -194,7 +239,7 @@
   ],
   extensions=[
   ],
-  nested_types=[],
+  nested_types=[_CROSTOOLRUNNERTESTREQUEST_DEVICE, ],
   enum_types=[
   ],
   serialized_options=None,
@@ -203,8 +248,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=731,
-  serialized_end=1001,
+  serialized_start=764,
+  serialized_end=1169,
 )
 
 
@@ -235,8 +280,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1003,
-  serialized_end=1095,
+  serialized_start=1171,
+  serialized_end=1263,
 )
 
 
@@ -262,6 +307,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='container_metadata_key', full_name='chromiumos.test.api.CrosToolRunnerTestFinderRequest.container_metadata_key', index=2,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -274,8 +326,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1097,
-  serialized_end=1205,
+  serialized_start=1266,
+  serialized_end=1406,
 )
 
 
@@ -306,8 +358,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1207,
-  serialized_end=1294,
+  serialized_start=1408,
+  serialized_end=1495,
 )
 
 _CROSTOOLRUNNERPROVISIONREQUEST_DEVICE.fields_by_name['dut'].message_type = chromiumos_dot_test_dot_lab_dot_api_dot_dut__pb2._DUT
@@ -316,9 +368,11 @@
 _CROSTOOLRUNNERPROVISIONREQUEST.fields_by_name['devices'].message_type = _CROSTOOLRUNNERPROVISIONREQUEST_DEVICE
 _CROSTOOLRUNNERPROVISIONREQUEST.fields_by_name['inventory_server'].message_type = chromiumos_dot_test_dot_lab_dot_api_dot_ip__endpoint__pb2._IPENDPOINT
 _CROSTOOLRUNNERPROVISIONRESPONSE.fields_by_name['responses'].message_type = chromiumos_dot_test_dot_api_dot_cros__provision__cli__pb2._CROSPROVISIONRESPONSE
+_CROSTOOLRUNNERTESTREQUEST_DEVICE.fields_by_name['dut'].message_type = chromiumos_dot_test_dot_lab_dot_api_dot_dut__pb2._DUT
+_CROSTOOLRUNNERTESTREQUEST_DEVICE.containing_type = _CROSTOOLRUNNERTESTREQUEST
 _CROSTOOLRUNNERTESTREQUEST.fields_by_name['test_suites'].message_type = chromiumos_dot_test_dot_api_dot_test__suite__pb2._TESTSUITE
-_CROSTOOLRUNNERTESTREQUEST.fields_by_name['primary_dut'].message_type = chromiumos_dot_test_dot_lab_dot_api_dot_dut__pb2._DUT
-_CROSTOOLRUNNERTESTREQUEST.fields_by_name['companion_duts'].message_type = chromiumos_dot_test_dot_lab_dot_api_dot_dut__pb2._DUT
+_CROSTOOLRUNNERTESTREQUEST.fields_by_name['primary_dut'].message_type = _CROSTOOLRUNNERTESTREQUEST_DEVICE
+_CROSTOOLRUNNERTESTREQUEST.fields_by_name['companion_duts'].message_type = _CROSTOOLRUNNERTESTREQUEST_DEVICE
 _CROSTOOLRUNNERTESTREQUEST.fields_by_name['inventory_server'].message_type = chromiumos_dot_test_dot_lab_dot_api_dot_ip__endpoint__pb2._IPENDPOINT
 _CROSTOOLRUNNERTESTRESPONSE.fields_by_name['test_case_results'].message_type = chromiumos_dot_test_dot_api_dot_test__case__result__pb2._TESTCASERESULT
 _CROSTOOLRUNNERTESTFINDERREQUEST.fields_by_name['test_suites'].message_type = chromiumos_dot_test_dot_api_dot_test__suite__pb2._TESTSUITE
@@ -354,11 +408,19 @@
 _sym_db.RegisterMessage(CrosToolRunnerProvisionResponse)
 
 CrosToolRunnerTestRequest = _reflection.GeneratedProtocolMessageType('CrosToolRunnerTestRequest', (_message.Message,), {
+
+  'Device' : _reflection.GeneratedProtocolMessageType('Device', (_message.Message,), {
+    'DESCRIPTOR' : _CROSTOOLRUNNERTESTREQUEST_DEVICE,
+    '__module__' : 'chromiumos.test.api.cros_tool_runner_cli_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.CrosToolRunnerTestRequest.Device)
+    })
+  ,
   'DESCRIPTOR' : _CROSTOOLRUNNERTESTREQUEST,
   '__module__' : 'chromiumos.test.api.cros_tool_runner_cli_pb2'
   # @@protoc_insertion_point(class_scope:chromiumos.test.api.CrosToolRunnerTestRequest)
   })
 _sym_db.RegisterMessage(CrosToolRunnerTestRequest)
+_sym_db.RegisterMessage(CrosToolRunnerTestRequest.Device)
 
 CrosToolRunnerTestResponse = _reflection.GeneratedProtocolMessageType('CrosToolRunnerTestResponse', (_message.Message,), {
   'DESCRIPTOR' : _CROSTOOLRUNNERTESTRESPONSE,
diff --git a/api/gen/chromiumos/test/api/dut_attribute_pb2.py b/api/gen/chromiumos/test/api/dut_attribute_pb2.py
index 8b96518..13ebc27 100644
--- a/api/gen/chromiumos/test/api/dut_attribute_pb2.py
+++ b/api/gen/chromiumos/test/api/dut_attribute_pb2.py
@@ -20,7 +20,7 @@
   syntax='proto3',
   serialized_options=b'Z-go.chromium.org/chromiumos/config/go/test/api',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n\'chromiumos/test/api/dut_attribute.proto\x12\x13\x63hromiumos.test.api\x1a)chromiumos/test/api/provision_state.proto\"\x8b\x04\n\x0c\x44utAttribute\x12\x30\n\x02id\x18\x01 \x01(\x0b\x32$.chromiumos.test.api.DutAttribute.Id\x12\x0f\n\x07\x61liases\x18\x02 \x03(\t\x12P\n\x12\x66lat_config_source\x18\x03 \x01(\x0b\x32\x32.chromiumos.test.api.DutAttribute.FlatConfigSourceH\x00\x12\x43\n\x0bhwid_source\x18\x04 \x01(\x0b\x32,.chromiumos.test.api.DutAttribute.HwidSourceH\x00\x12\x16\n\x0e\x61llowed_values\x18\x05 \x03(\t\x12\x16\n\x0e\x65xclude_values\x18\x06 \x03(\t\x1a\x13\n\x02Id\x12\r\n\x05value\x18\x01 \x01(\t\x1a\x19\n\tFieldSpec\x12\x0c\n\x04path\x18\x01 \x01(\t\x1aO\n\x10\x46latConfigSource\x12;\n\x06\x66ields\x18\x01 \x03(\x0b\x32+.chromiumos.test.api.DutAttribute.FieldSpec\x1a\x61\n\nHwidSource\x12\x16\n\x0e\x63omponent_type\x18\x01 \x01(\t\x12;\n\x06\x66ields\x18\x02 \x03(\x0b\x32+.chromiumos.test.api.DutAttribute.FieldSpecB\r\n\x0b\x64\x61ta_source\"M\n\x10\x44utAttributeList\x12\x39\n\x0e\x64ut_attributes\x18\x01 \x03(\x0b\x32!.chromiumos.test.api.DutAttribute\"Z\n\x0c\x44utCriterion\x12:\n\x0c\x61ttribute_id\x18\x01 \x01(\x0b\x32$.chromiumos.test.api.DutAttribute.Id\x12\x0e\n\x06values\x18\x02 \x03(\t\"\x80\x01\n\tDutTarget\x12\x33\n\x08\x63riteria\x18\x01 \x03(\x0b\x32!.chromiumos.test.api.DutCriterion\x12>\n\x10provision_config\x18\x02 \x01(\x0b\x32$.chromiumos.test.api.ProvisionConfigB/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
+  serialized_pb=b'\n\'chromiumos/test/api/dut_attribute.proto\x12\x13\x63hromiumos.test.api\x1a)chromiumos/test/api/provision_state.proto\"\xdb\x04\n\x0c\x44utAttribute\x12\x30\n\x02id\x18\x01 \x01(\x0b\x32$.chromiumos.test.api.DutAttribute.Id\x12\x0f\n\x07\x61liases\x18\x02 \x03(\t\x12P\n\x12\x66lat_config_source\x18\x03 \x01(\x0b\x32\x32.chromiumos.test.api.DutAttribute.FlatConfigSourceH\x00\x12\x43\n\x0bhwid_source\x18\x04 \x01(\x0b\x32,.chromiumos.test.api.DutAttribute.HwidSourceH\x00\x12\x41\n\ntle_source\x18\x07 \x01(\x0b\x32+.chromiumos.test.api.DutAttribute.TleSourceH\x00\x12\x16\n\x0e\x61llowed_values\x18\x05 \x03(\t\x12\x16\n\x0e\x65xclude_values\x18\x06 \x03(\t\x1a\x13\n\x02Id\x12\r\n\x05value\x18\x01 \x01(\t\x1a\x19\n\tFieldSpec\x12\x0c\n\x04path\x18\x01 \x01(\t\x1aO\n\x10\x46latConfigSource\x12;\n\x06\x66ields\x18\x01 \x03(\x0b\x32+.chromiumos.test.api.DutAttribute.FieldSpec\x1a\x61\n\nHwidSource\x12\x16\n\x0e\x63omponent_type\x18\x01 \x01(\t\x12;\n\x06\x66ields\x18\x02 \x03(\x0b\x32+.chromiumos.test.api.DutAttribute.FieldSpec\x1a\x0b\n\tTleSourceB\r\n\x0b\x64\x61ta_source\"M\n\x10\x44utAttributeList\x12\x39\n\x0e\x64ut_attributes\x18\x01 \x03(\x0b\x32!.chromiumos.test.api.DutAttribute\"Z\n\x0c\x44utCriterion\x12:\n\x0c\x61ttribute_id\x18\x01 \x01(\x0b\x32$.chromiumos.test.api.DutAttribute.Id\x12\x0e\n\x06values\x18\x02 \x03(\t\"\x80\x01\n\tDutTarget\x12\x33\n\x08\x63riteria\x18\x01 \x03(\x0b\x32!.chromiumos.test.api.DutCriterion\x12>\n\x10provision_config\x18\x02 \x01(\x0b\x32$.chromiumos.test.api.ProvisionConfigB/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
   ,
   dependencies=[chromiumos_dot_test_dot_api_dot_provision__state__pb2.DESCRIPTOR,])
 
@@ -54,8 +54,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=390,
-  serialized_end=409,
+  serialized_start=457,
+  serialized_end=476,
 )
 
 _DUTATTRIBUTE_FIELDSPEC = _descriptor.Descriptor(
@@ -85,8 +85,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=411,
-  serialized_end=436,
+  serialized_start=478,
+  serialized_end=503,
 )
 
 _DUTATTRIBUTE_FLATCONFIGSOURCE = _descriptor.Descriptor(
@@ -116,8 +116,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=438,
-  serialized_end=517,
+  serialized_start=505,
+  serialized_end=584,
 )
 
 _DUTATTRIBUTE_HWIDSOURCE = _descriptor.Descriptor(
@@ -154,8 +154,32 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=519,
-  serialized_end=616,
+  serialized_start=586,
+  serialized_end=683,
+)
+
+_DUTATTRIBUTE_TLESOURCE = _descriptor.Descriptor(
+  name='TleSource',
+  full_name='chromiumos.test.api.DutAttribute.TleSource',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=685,
+  serialized_end=696,
 )
 
 _DUTATTRIBUTE = _descriptor.Descriptor(
@@ -195,14 +219,21 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='allowed_values', full_name='chromiumos.test.api.DutAttribute.allowed_values', index=4,
+      name='tle_source', full_name='chromiumos.test.api.DutAttribute.tle_source', index=4,
+      number=7, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='allowed_values', full_name='chromiumos.test.api.DutAttribute.allowed_values', index=5,
       number=5, type=9, cpp_type=9, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='exclude_values', full_name='chromiumos.test.api.DutAttribute.exclude_values', index=5,
+      name='exclude_values', full_name='chromiumos.test.api.DutAttribute.exclude_values', index=6,
       number=6, type=9, cpp_type=9, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
@@ -211,7 +242,7 @@
   ],
   extensions=[
   ],
-  nested_types=[_DUTATTRIBUTE_ID, _DUTATTRIBUTE_FIELDSPEC, _DUTATTRIBUTE_FLATCONFIGSOURCE, _DUTATTRIBUTE_HWIDSOURCE, ],
+  nested_types=[_DUTATTRIBUTE_ID, _DUTATTRIBUTE_FIELDSPEC, _DUTATTRIBUTE_FLATCONFIGSOURCE, _DUTATTRIBUTE_HWIDSOURCE, _DUTATTRIBUTE_TLESOURCE, ],
   enum_types=[
   ],
   serialized_options=None,
@@ -226,7 +257,7 @@
     fields=[]),
   ],
   serialized_start=108,
-  serialized_end=631,
+  serialized_end=711,
 )
 
 
@@ -257,8 +288,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=633,
-  serialized_end=710,
+  serialized_start=713,
+  serialized_end=790,
 )
 
 
@@ -296,8 +327,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=712,
-  serialized_end=802,
+  serialized_start=792,
+  serialized_end=882,
 )
 
 
@@ -335,8 +366,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=805,
-  serialized_end=933,
+  serialized_start=885,
+  serialized_end=1013,
 )
 
 _DUTATTRIBUTE_ID.containing_type = _DUTATTRIBUTE
@@ -345,15 +376,20 @@
 _DUTATTRIBUTE_FLATCONFIGSOURCE.containing_type = _DUTATTRIBUTE
 _DUTATTRIBUTE_HWIDSOURCE.fields_by_name['fields'].message_type = _DUTATTRIBUTE_FIELDSPEC
 _DUTATTRIBUTE_HWIDSOURCE.containing_type = _DUTATTRIBUTE
+_DUTATTRIBUTE_TLESOURCE.containing_type = _DUTATTRIBUTE
 _DUTATTRIBUTE.fields_by_name['id'].message_type = _DUTATTRIBUTE_ID
 _DUTATTRIBUTE.fields_by_name['flat_config_source'].message_type = _DUTATTRIBUTE_FLATCONFIGSOURCE
 _DUTATTRIBUTE.fields_by_name['hwid_source'].message_type = _DUTATTRIBUTE_HWIDSOURCE
+_DUTATTRIBUTE.fields_by_name['tle_source'].message_type = _DUTATTRIBUTE_TLESOURCE
 _DUTATTRIBUTE.oneofs_by_name['data_source'].fields.append(
   _DUTATTRIBUTE.fields_by_name['flat_config_source'])
 _DUTATTRIBUTE.fields_by_name['flat_config_source'].containing_oneof = _DUTATTRIBUTE.oneofs_by_name['data_source']
 _DUTATTRIBUTE.oneofs_by_name['data_source'].fields.append(
   _DUTATTRIBUTE.fields_by_name['hwid_source'])
 _DUTATTRIBUTE.fields_by_name['hwid_source'].containing_oneof = _DUTATTRIBUTE.oneofs_by_name['data_source']
+_DUTATTRIBUTE.oneofs_by_name['data_source'].fields.append(
+  _DUTATTRIBUTE.fields_by_name['tle_source'])
+_DUTATTRIBUTE.fields_by_name['tle_source'].containing_oneof = _DUTATTRIBUTE.oneofs_by_name['data_source']
 _DUTATTRIBUTELIST.fields_by_name['dut_attributes'].message_type = _DUTATTRIBUTE
 _DUTCRITERION.fields_by_name['attribute_id'].message_type = _DUTATTRIBUTE_ID
 _DUTTARGET.fields_by_name['criteria'].message_type = _DUTCRITERION
@@ -393,6 +429,13 @@
     # @@protoc_insertion_point(class_scope:chromiumos.test.api.DutAttribute.HwidSource)
     })
   ,
+
+  'TleSource' : _reflection.GeneratedProtocolMessageType('TleSource', (_message.Message,), {
+    'DESCRIPTOR' : _DUTATTRIBUTE_TLESOURCE,
+    '__module__' : 'chromiumos.test.api.dut_attribute_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.DutAttribute.TleSource)
+    })
+  ,
   'DESCRIPTOR' : _DUTATTRIBUTE,
   '__module__' : 'chromiumos.test.api.dut_attribute_pb2'
   # @@protoc_insertion_point(class_scope:chromiumos.test.api.DutAttribute)
@@ -402,6 +445,7 @@
 _sym_db.RegisterMessage(DutAttribute.FieldSpec)
 _sym_db.RegisterMessage(DutAttribute.FlatConfigSource)
 _sym_db.RegisterMessage(DutAttribute.HwidSource)
+_sym_db.RegisterMessage(DutAttribute.TleSource)
 
 DutAttributeList = _reflection.GeneratedProtocolMessageType('DutAttributeList', (_message.Message,), {
   'DESCRIPTOR' : _DUTATTRIBUTELIST,
diff --git a/api/gen/chromiumos/test/api/dut_service_pb2.py b/api/gen/chromiumos/test/api/dut_service_pb2.py
index c7612fe..b5a42a6 100644
--- a/api/gen/chromiumos/test/api/dut_service_pb2.py
+++ b/api/gen/chromiumos/test/api/dut_service_pb2.py
@@ -22,7 +22,7 @@
   syntax='proto3',
   serialized_options=b'Z-go.chromium.org/chromiumos/config/go/test/api',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n%chromiumos/test/api/dut_service.proto\x12\x13\x63hromiumos.test.api\x1a,chromiumos/config/api/device_config_id.proto\x1a\'chromiumos/longrunning/operations.proto\"\xaa\x01\n\x12\x45xecCommandRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07\x63ommand\x18\x02 \x01(\t\x12\x0c\n\x04\x61rgs\x18\x03 \x03(\t\x12\r\n\x05stdin\x18\x04 \x01(\x0c\x12+\n\x06stdout\x18\x05 \x01(\x0e\x32\x1b.chromiumos.test.api.Output\x12+\n\x06stderr\x18\x06 \x01(\x0e\x32\x1b.chromiumos.test.api.Output\"\xd1\x01\n\x13\x45xecCommandResponse\x12\x44\n\texit_info\x18\x01 \x01(\x0b\x32\x31.chromiumos.test.api.ExecCommandResponse.ExitInfo\x12\x0e\n\x06stdout\x18\x02 \x01(\x0c\x12\x0e\n\x06stderr\x18\x03 \x01(\x0c\x1aT\n\x08\x45xitInfo\x12\x0e\n\x06status\x18\x01 \x01(\x05\x12\x10\n\x08signaled\x18\x02 \x01(\x08\x12\x0f\n\x07started\x18\x03 \x01(\x08\x12\x15\n\rerror_message\x18\x04 \x01(\t\"/\n\x13\x46\x65tchCrashesRequest\x12\x12\n\nfetch_core\x18\x02 \x01(\x08J\x04\x08\x01\x10\x02\"\xa1\x01\n\x14\x46\x65tchCrashesResponse\x12\x10\n\x08\x63rash_id\x18\x01 \x01(\x03\x12/\n\x05\x63rash\x18\x02 \x01(\x0b\x32\x1e.chromiumos.test.api.CrashInfoH\x00\x12.\n\x04\x62lob\x18\x03 \x01(\x0b\x32\x1e.chromiumos.test.api.CrashBlobH\x00\x12\x0e\n\x04\x63ore\x18\x04 \x01(\x0cH\x00\x42\x06\n\x04\x64\x61ta\"\xb3\x01\n\tCrashInfo\x12\x11\n\texec_name\x18\x01 \x01(\t\x12\x0c\n\x04prod\x18\x02 \x01(\t\x12\x0b\n\x03ver\x18\x03 \x01(\t\x12\x0b\n\x03sig\x18\x04 \x01(\t\x12$\n\x1cin_progress_integration_test\x18\x05 \x01(\t\x12\x11\n\tcollector\x18\x06 \x01(\t\x12\x32\n\x06\x66ields\x18\x07 \x03(\x0b\x32\".chromiumos.test.api.CrashMetadata\"*\n\rCrashMetadata\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x0c\n\x04text\x18\x02 \x01(\t\"8\n\tCrashBlob\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x0c\n\x04\x62lob\x18\x02 \x01(\x0c\x12\x10\n\x08\x66ilename\x18\x03 \x01(\t\"\x1e\n\x0eRestartRequest\x12\x0c\n\x04\x61rgs\x18\x01 \x03(\t\"!\n\x0fRestartResponse\x12\x0e\n\x06output\x18\x01 \x01(\t\"\x11\n\x0fRestartMetadata\"\x1d\n\x1b\x44\x65tectDeviceConfigIdRequest\"\xc1\x02\n\x1c\x44\x65tectDeviceConfigIdResponse\x12L\n\x07success\x18\x01 \x01(\x0b\x32\x39.chromiumos.test.api.DetectDeviceConfigIdResponse.SuccessH\x00\x12L\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32\x39.chromiumos.test.api.DetectDeviceConfigIdResponse.FailureH\x00\x1aY\n\x07Success\x12N\n\x14\x64\x65tected_scan_config\x18\x01 \x01(\x0b\x32\x30.chromiumos.config.api.DeviceConfigId.ScanConfig\x1a \n\x07\x46\x61ilure\x12\x15\n\rerror_message\x18\x01 \x01(\tB\x08\n\x06result*,\n\x06Output\x12\x0f\n\x0bOUTPUT_PIPE\x10\x00\x12\x11\n\rOUTPUT_STDOUT\x10\x01\x32\xd0\x03\n\nDutService\x12\x62\n\x0b\x45xecCommand\x12\'.chromiumos.test.api.ExecCommandRequest\x1a(.chromiumos.test.api.ExecCommandResponse0\x01\x12\x65\n\x0c\x46\x65tchCrashes\x12(.chromiumos.test.api.FetchCrashesRequest\x1a).chromiumos.test.api.FetchCrashesResponse0\x01\x12x\n\x07Restart\x12#.chromiumos.test.api.RestartRequest\x1a!.chromiumos.longrunning.Operation\"%\xd2\x41\"\n\x0fRestartResponse\x12\x0fRestartMetadata\x12}\n\x14\x44\x65tectDeviceConfigId\x12\x30.chromiumos.test.api.DetectDeviceConfigIdRequest\x1a\x31.chromiumos.test.api.DetectDeviceConfigIdResponse0\x01\x42/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
+  serialized_pb=b'\n%chromiumos/test/api/dut_service.proto\x12\x13\x63hromiumos.test.api\x1a,chromiumos/config/api/device_config_id.proto\x1a\'chromiumos/longrunning/operations.proto\"\xaa\x01\n\x12\x45xecCommandRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07\x63ommand\x18\x02 \x01(\t\x12\x0c\n\x04\x61rgs\x18\x03 \x03(\t\x12\r\n\x05stdin\x18\x04 \x01(\x0c\x12+\n\x06stdout\x18\x05 \x01(\x0e\x32\x1b.chromiumos.test.api.Output\x12+\n\x06stderr\x18\x06 \x01(\x0e\x32\x1b.chromiumos.test.api.Output\"\xd1\x01\n\x13\x45xecCommandResponse\x12\x44\n\texit_info\x18\x01 \x01(\x0b\x32\x31.chromiumos.test.api.ExecCommandResponse.ExitInfo\x12\x0e\n\x06stdout\x18\x02 \x01(\x0c\x12\x0e\n\x06stderr\x18\x03 \x01(\x0c\x1aT\n\x08\x45xitInfo\x12\x0e\n\x06status\x18\x01 \x01(\x05\x12\x10\n\x08signaled\x18\x02 \x01(\x08\x12\x0f\n\x07started\x18\x03 \x01(\x08\x12\x15\n\rerror_message\x18\x04 \x01(\t\"/\n\x13\x46\x65tchCrashesRequest\x12\x12\n\nfetch_core\x18\x02 \x01(\x08J\x04\x08\x01\x10\x02\"\xa1\x01\n\x14\x46\x65tchCrashesResponse\x12\x10\n\x08\x63rash_id\x18\x01 \x01(\x03\x12/\n\x05\x63rash\x18\x02 \x01(\x0b\x32\x1e.chromiumos.test.api.CrashInfoH\x00\x12.\n\x04\x62lob\x18\x03 \x01(\x0b\x32\x1e.chromiumos.test.api.CrashBlobH\x00\x12\x0e\n\x04\x63ore\x18\x04 \x01(\x0cH\x00\x42\x06\n\x04\x64\x61ta\"\xb3\x01\n\tCrashInfo\x12\x11\n\texec_name\x18\x01 \x01(\t\x12\x0c\n\x04prod\x18\x02 \x01(\t\x12\x0b\n\x03ver\x18\x03 \x01(\t\x12\x0b\n\x03sig\x18\x04 \x01(\t\x12$\n\x1cin_progress_integration_test\x18\x05 \x01(\t\x12\x11\n\tcollector\x18\x06 \x01(\t\x12\x32\n\x06\x66ields\x18\x07 \x03(\x0b\x32\".chromiumos.test.api.CrashMetadata\"*\n\rCrashMetadata\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x0c\n\x04text\x18\x02 \x01(\t\"8\n\tCrashBlob\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x0c\n\x04\x62lob\x18\x02 \x01(\x0c\x12\x10\n\x08\x66ilename\x18\x03 \x01(\t\"\x1e\n\x0eRestartRequest\x12\x0c\n\x04\x61rgs\x18\x01 \x03(\t\"!\n\x0fRestartResponse\x12\x0e\n\x06output\x18\x01 \x01(\t\"\x11\n\x0fRestartMetadata\"\x8e\x04\n\x0c\x43\x61\x63heRequest\x12;\n\x04\x66ile\x18\x01 \x01(\x0b\x32+.chromiumos.test.api.CacheRequest.LocalFileH\x00\x12\x36\n\x04pipe\x18\x02 \x01(\x0b\x32&.chromiumos.test.api.CacheRequest.PipeH\x00\x12;\n\x07gs_file\x18\x03 \x01(\x0b\x32(.chromiumos.test.api.CacheRequest.GSFileH\x01\x12\x42\n\x0bgs_zip_file\x18\x04 \x01(\x0b\x32+.chromiumos.test.api.CacheRequest.GSZipFileH\x01\x12\x42\n\x0bgs_tar_file\x18\x05 \x01(\x0b\x32+.chromiumos.test.api.CacheRequest.GSTARFileH\x01\x1a\x19\n\tLocalFile\x12\x0c\n\x04path\x18\x01 \x01(\t\x1a\x18\n\x04Pipe\x12\x10\n\x08\x63ommands\x18\x01 \x01(\t\x1a\x1d\n\x06GSFile\x12\x13\n\x0bsource_path\x18\x01 \x01(\t\x1a \n\tGSZipFile\x12\x13\n\x0bsource_path\x18\x01 \x01(\t\x1a\x35\n\tGSTARFile\x12\x13\n\x0bsource_path\x18\x01 \x01(\t\x12\x13\n\x0bsource_file\x18\x02 \x01(\tB\r\n\x0b\x64\x65stinationB\x08\n\x06source\"\xc4\x01\n\rCacheResponse\x12=\n\x07success\x18\x01 \x01(\x0b\x32*.chromiumos.test.api.CacheResponse.SuccessH\x00\x12=\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32*.chromiumos.test.api.CacheResponse.FailureH\x00\x1a\t\n\x07Success\x1a \n\x07\x46\x61ilure\x12\x15\n\rerror_message\x18\x01 \x01(\tB\x08\n\x06result\"\x0f\n\rCacheMetadata\"\x17\n\x15\x46orceReconnectRequest\"\xdf\x01\n\x16\x46orceReconnectResponse\x12\x46\n\x07success\x18\x01 \x01(\x0b\x32\x33.chromiumos.test.api.ForceReconnectResponse.SuccessH\x00\x12\x46\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32\x33.chromiumos.test.api.ForceReconnectResponse.FailureH\x00\x1a\t\n\x07Success\x1a \n\x07\x46\x61ilure\x12\x15\n\rerror_message\x18\x01 \x01(\tB\x08\n\x06result\"\x18\n\x16\x46orceReconnectMetadata\"\x1d\n\x1b\x44\x65tectDeviceConfigIdRequest\"\xc1\x02\n\x1c\x44\x65tectDeviceConfigIdResponse\x12L\n\x07success\x18\x01 \x01(\x0b\x32\x39.chromiumos.test.api.DetectDeviceConfigIdResponse.SuccessH\x00\x12L\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32\x39.chromiumos.test.api.DetectDeviceConfigIdResponse.FailureH\x00\x1aY\n\x07Success\x12N\n\x14\x64\x65tected_scan_config\x18\x01 \x01(\x0b\x32\x30.chromiumos.config.api.DeviceConfigId.ScanConfig\x1a \n\x07\x46\x61ilure\x12\x15\n\rerror_message\x18\x01 \x01(\tB\x08\n\x06result*,\n\x06Output\x12\x0f\n\x0bOUTPUT_PIPE\x10\x00\x12\x11\n\rOUTPUT_STDOUT\x10\x01\x32\xd9\x05\n\nDutService\x12\x62\n\x0b\x45xecCommand\x12\'.chromiumos.test.api.ExecCommandRequest\x1a(.chromiumos.test.api.ExecCommandResponse0\x01\x12\x65\n\x0c\x46\x65tchCrashes\x12(.chromiumos.test.api.FetchCrashesRequest\x1a).chromiumos.test.api.FetchCrashesResponse0\x01\x12x\n\x07Restart\x12#.chromiumos.test.api.RestartRequest\x1a!.chromiumos.longrunning.Operation\"%\xd2\x41\"\n\x0fRestartResponse\x12\x0fRestartMetadata\x12}\n\x14\x44\x65tectDeviceConfigId\x12\x30.chromiumos.test.api.DetectDeviceConfigIdRequest\x1a\x31.chromiumos.test.api.DetectDeviceConfigIdResponse0\x01\x12p\n\x05\x43\x61\x63he\x12!.chromiumos.test.api.CacheRequest\x1a!.chromiumos.longrunning.Operation\"!\xd2\x41\x1e\n\rCacheResponse\x12\rCacheMetadata\x12\x94\x01\n\x0e\x46orceReconnect\x12*.chromiumos.test.api.ForceReconnectRequest\x1a!.chromiumos.longrunning.Operation\"3\xd2\x41\x30\n\x16\x46orceReconnectResponse\x12\x16\x46orceReconnectMetadataB/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
   ,
   dependencies=[chromiumos_dot_config_dot_api_dot_device__config__id__pb2.DESCRIPTOR,chromiumos_dot_longrunning_dot_operations__pb2.DESCRIPTOR,])
 
@@ -46,8 +46,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1472,
-  serialized_end=1516,
+  serialized_start=2494,
+  serialized_end=2538,
 )
 _sym_db.RegisterEnumDescriptor(_OUTPUT)
 
@@ -560,6 +560,511 @@
 )
 
 
+_CACHEREQUEST_LOCALFILE = _descriptor.Descriptor(
+  name='LocalFile',
+  full_name='chromiumos.test.api.CacheRequest.LocalFile',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='path', full_name='chromiumos.test.api.CacheRequest.LocalFile.path', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1448,
+  serialized_end=1473,
+)
+
+_CACHEREQUEST_PIPE = _descriptor.Descriptor(
+  name='Pipe',
+  full_name='chromiumos.test.api.CacheRequest.Pipe',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='commands', full_name='chromiumos.test.api.CacheRequest.Pipe.commands', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1475,
+  serialized_end=1499,
+)
+
+_CACHEREQUEST_GSFILE = _descriptor.Descriptor(
+  name='GSFile',
+  full_name='chromiumos.test.api.CacheRequest.GSFile',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='source_path', full_name='chromiumos.test.api.CacheRequest.GSFile.source_path', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1501,
+  serialized_end=1530,
+)
+
+_CACHEREQUEST_GSZIPFILE = _descriptor.Descriptor(
+  name='GSZipFile',
+  full_name='chromiumos.test.api.CacheRequest.GSZipFile',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='source_path', full_name='chromiumos.test.api.CacheRequest.GSZipFile.source_path', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1532,
+  serialized_end=1564,
+)
+
+_CACHEREQUEST_GSTARFILE = _descriptor.Descriptor(
+  name='GSTARFile',
+  full_name='chromiumos.test.api.CacheRequest.GSTARFile',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='source_path', full_name='chromiumos.test.api.CacheRequest.GSTARFile.source_path', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='source_file', full_name='chromiumos.test.api.CacheRequest.GSTARFile.source_file', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1566,
+  serialized_end=1619,
+)
+
+_CACHEREQUEST = _descriptor.Descriptor(
+  name='CacheRequest',
+  full_name='chromiumos.test.api.CacheRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='file', full_name='chromiumos.test.api.CacheRequest.file', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='pipe', full_name='chromiumos.test.api.CacheRequest.pipe', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='gs_file', full_name='chromiumos.test.api.CacheRequest.gs_file', index=2,
+      number=3, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='gs_zip_file', full_name='chromiumos.test.api.CacheRequest.gs_zip_file', index=3,
+      number=4, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='gs_tar_file', full_name='chromiumos.test.api.CacheRequest.gs_tar_file', index=4,
+      number=5, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[_CACHEREQUEST_LOCALFILE, _CACHEREQUEST_PIPE, _CACHEREQUEST_GSFILE, _CACHEREQUEST_GSZIPFILE, _CACHEREQUEST_GSTARFILE, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+    _descriptor.OneofDescriptor(
+      name='destination', full_name='chromiumos.test.api.CacheRequest.destination',
+      index=0, containing_type=None,
+      create_key=_descriptor._internal_create_key,
+    fields=[]),
+    _descriptor.OneofDescriptor(
+      name='source', full_name='chromiumos.test.api.CacheRequest.source',
+      index=1, containing_type=None,
+      create_key=_descriptor._internal_create_key,
+    fields=[]),
+  ],
+  serialized_start=1118,
+  serialized_end=1644,
+)
+
+
+_CACHERESPONSE_SUCCESS = _descriptor.Descriptor(
+  name='Success',
+  full_name='chromiumos.test.api.CacheResponse.Success',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1790,
+  serialized_end=1799,
+)
+
+_CACHERESPONSE_FAILURE = _descriptor.Descriptor(
+  name='Failure',
+  full_name='chromiumos.test.api.CacheResponse.Failure',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='error_message', full_name='chromiumos.test.api.CacheResponse.Failure.error_message', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1801,
+  serialized_end=1833,
+)
+
+_CACHERESPONSE = _descriptor.Descriptor(
+  name='CacheResponse',
+  full_name='chromiumos.test.api.CacheResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='success', full_name='chromiumos.test.api.CacheResponse.success', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='failure', full_name='chromiumos.test.api.CacheResponse.failure', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[_CACHERESPONSE_SUCCESS, _CACHERESPONSE_FAILURE, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+    _descriptor.OneofDescriptor(
+      name='result', full_name='chromiumos.test.api.CacheResponse.result',
+      index=0, containing_type=None,
+      create_key=_descriptor._internal_create_key,
+    fields=[]),
+  ],
+  serialized_start=1647,
+  serialized_end=1843,
+)
+
+
+_CACHEMETADATA = _descriptor.Descriptor(
+  name='CacheMetadata',
+  full_name='chromiumos.test.api.CacheMetadata',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1845,
+  serialized_end=1860,
+)
+
+
+_FORCERECONNECTREQUEST = _descriptor.Descriptor(
+  name='ForceReconnectRequest',
+  full_name='chromiumos.test.api.ForceReconnectRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1862,
+  serialized_end=1885,
+)
+
+
+_FORCERECONNECTRESPONSE_SUCCESS = _descriptor.Descriptor(
+  name='Success',
+  full_name='chromiumos.test.api.ForceReconnectResponse.Success',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1790,
+  serialized_end=1799,
+)
+
+_FORCERECONNECTRESPONSE_FAILURE = _descriptor.Descriptor(
+  name='Failure',
+  full_name='chromiumos.test.api.ForceReconnectResponse.Failure',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='error_message', full_name='chromiumos.test.api.ForceReconnectResponse.Failure.error_message', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1801,
+  serialized_end=1833,
+)
+
+_FORCERECONNECTRESPONSE = _descriptor.Descriptor(
+  name='ForceReconnectResponse',
+  full_name='chromiumos.test.api.ForceReconnectResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='success', full_name='chromiumos.test.api.ForceReconnectResponse.success', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='failure', full_name='chromiumos.test.api.ForceReconnectResponse.failure', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[_FORCERECONNECTRESPONSE_SUCCESS, _FORCERECONNECTRESPONSE_FAILURE, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+    _descriptor.OneofDescriptor(
+      name='result', full_name='chromiumos.test.api.ForceReconnectResponse.result',
+      index=0, containing_type=None,
+      create_key=_descriptor._internal_create_key,
+    fields=[]),
+  ],
+  serialized_start=1888,
+  serialized_end=2111,
+)
+
+
+_FORCERECONNECTMETADATA = _descriptor.Descriptor(
+  name='ForceReconnectMetadata',
+  full_name='chromiumos.test.api.ForceReconnectMetadata',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2113,
+  serialized_end=2137,
+)
+
+
 _DETECTDEVICECONFIGIDREQUEST = _descriptor.Descriptor(
   name='DetectDeviceConfigIdRequest',
   full_name='chromiumos.test.api.DetectDeviceConfigIdRequest',
@@ -580,8 +1085,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1117,
-  serialized_end=1146,
+  serialized_start=2139,
+  serialized_end=2168,
 )
 
 
@@ -612,8 +1117,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1337,
-  serialized_end=1426,
+  serialized_start=2359,
+  serialized_end=2448,
 )
 
 _DETECTDEVICECONFIGIDRESPONSE_FAILURE = _descriptor.Descriptor(
@@ -643,8 +1148,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1428,
-  serialized_end=1460,
+  serialized_start=1801,
+  serialized_end=1833,
 )
 
 _DETECTDEVICECONFIGIDRESPONSE = _descriptor.Descriptor(
@@ -686,8 +1191,8 @@
       create_key=_descriptor._internal_create_key,
     fields=[]),
   ],
-  serialized_start=1149,
-  serialized_end=1470,
+  serialized_start=2171,
+  serialized_end=2492,
 )
 
 _EXECCOMMANDREQUEST.fields_by_name['stdout'].enum_type = _OUTPUT
@@ -706,6 +1211,51 @@
   _FETCHCRASHESRESPONSE.fields_by_name['core'])
 _FETCHCRASHESRESPONSE.fields_by_name['core'].containing_oneof = _FETCHCRASHESRESPONSE.oneofs_by_name['data']
 _CRASHINFO.fields_by_name['fields'].message_type = _CRASHMETADATA
+_CACHEREQUEST_LOCALFILE.containing_type = _CACHEREQUEST
+_CACHEREQUEST_PIPE.containing_type = _CACHEREQUEST
+_CACHEREQUEST_GSFILE.containing_type = _CACHEREQUEST
+_CACHEREQUEST_GSZIPFILE.containing_type = _CACHEREQUEST
+_CACHEREQUEST_GSTARFILE.containing_type = _CACHEREQUEST
+_CACHEREQUEST.fields_by_name['file'].message_type = _CACHEREQUEST_LOCALFILE
+_CACHEREQUEST.fields_by_name['pipe'].message_type = _CACHEREQUEST_PIPE
+_CACHEREQUEST.fields_by_name['gs_file'].message_type = _CACHEREQUEST_GSFILE
+_CACHEREQUEST.fields_by_name['gs_zip_file'].message_type = _CACHEREQUEST_GSZIPFILE
+_CACHEREQUEST.fields_by_name['gs_tar_file'].message_type = _CACHEREQUEST_GSTARFILE
+_CACHEREQUEST.oneofs_by_name['destination'].fields.append(
+  _CACHEREQUEST.fields_by_name['file'])
+_CACHEREQUEST.fields_by_name['file'].containing_oneof = _CACHEREQUEST.oneofs_by_name['destination']
+_CACHEREQUEST.oneofs_by_name['destination'].fields.append(
+  _CACHEREQUEST.fields_by_name['pipe'])
+_CACHEREQUEST.fields_by_name['pipe'].containing_oneof = _CACHEREQUEST.oneofs_by_name['destination']
+_CACHEREQUEST.oneofs_by_name['source'].fields.append(
+  _CACHEREQUEST.fields_by_name['gs_file'])
+_CACHEREQUEST.fields_by_name['gs_file'].containing_oneof = _CACHEREQUEST.oneofs_by_name['source']
+_CACHEREQUEST.oneofs_by_name['source'].fields.append(
+  _CACHEREQUEST.fields_by_name['gs_zip_file'])
+_CACHEREQUEST.fields_by_name['gs_zip_file'].containing_oneof = _CACHEREQUEST.oneofs_by_name['source']
+_CACHEREQUEST.oneofs_by_name['source'].fields.append(
+  _CACHEREQUEST.fields_by_name['gs_tar_file'])
+_CACHEREQUEST.fields_by_name['gs_tar_file'].containing_oneof = _CACHEREQUEST.oneofs_by_name['source']
+_CACHERESPONSE_SUCCESS.containing_type = _CACHERESPONSE
+_CACHERESPONSE_FAILURE.containing_type = _CACHERESPONSE
+_CACHERESPONSE.fields_by_name['success'].message_type = _CACHERESPONSE_SUCCESS
+_CACHERESPONSE.fields_by_name['failure'].message_type = _CACHERESPONSE_FAILURE
+_CACHERESPONSE.oneofs_by_name['result'].fields.append(
+  _CACHERESPONSE.fields_by_name['success'])
+_CACHERESPONSE.fields_by_name['success'].containing_oneof = _CACHERESPONSE.oneofs_by_name['result']
+_CACHERESPONSE.oneofs_by_name['result'].fields.append(
+  _CACHERESPONSE.fields_by_name['failure'])
+_CACHERESPONSE.fields_by_name['failure'].containing_oneof = _CACHERESPONSE.oneofs_by_name['result']
+_FORCERECONNECTRESPONSE_SUCCESS.containing_type = _FORCERECONNECTRESPONSE
+_FORCERECONNECTRESPONSE_FAILURE.containing_type = _FORCERECONNECTRESPONSE
+_FORCERECONNECTRESPONSE.fields_by_name['success'].message_type = _FORCERECONNECTRESPONSE_SUCCESS
+_FORCERECONNECTRESPONSE.fields_by_name['failure'].message_type = _FORCERECONNECTRESPONSE_FAILURE
+_FORCERECONNECTRESPONSE.oneofs_by_name['result'].fields.append(
+  _FORCERECONNECTRESPONSE.fields_by_name['success'])
+_FORCERECONNECTRESPONSE.fields_by_name['success'].containing_oneof = _FORCERECONNECTRESPONSE.oneofs_by_name['result']
+_FORCERECONNECTRESPONSE.oneofs_by_name['result'].fields.append(
+  _FORCERECONNECTRESPONSE.fields_by_name['failure'])
+_FORCERECONNECTRESPONSE.fields_by_name['failure'].containing_oneof = _FORCERECONNECTRESPONSE.oneofs_by_name['result']
 _DETECTDEVICECONFIGIDRESPONSE_SUCCESS.fields_by_name['detected_scan_config'].message_type = chromiumos_dot_config_dot_api_dot_device__config__id__pb2._DEVICECONFIGID_SCANCONFIG
 _DETECTDEVICECONFIGIDRESPONSE_SUCCESS.containing_type = _DETECTDEVICECONFIGIDRESPONSE
 _DETECTDEVICECONFIGIDRESPONSE_FAILURE.containing_type = _DETECTDEVICECONFIGIDRESPONSE
@@ -727,6 +1277,12 @@
 DESCRIPTOR.message_types_by_name['RestartRequest'] = _RESTARTREQUEST
 DESCRIPTOR.message_types_by_name['RestartResponse'] = _RESTARTRESPONSE
 DESCRIPTOR.message_types_by_name['RestartMetadata'] = _RESTARTMETADATA
+DESCRIPTOR.message_types_by_name['CacheRequest'] = _CACHEREQUEST
+DESCRIPTOR.message_types_by_name['CacheResponse'] = _CACHERESPONSE
+DESCRIPTOR.message_types_by_name['CacheMetadata'] = _CACHEMETADATA
+DESCRIPTOR.message_types_by_name['ForceReconnectRequest'] = _FORCERECONNECTREQUEST
+DESCRIPTOR.message_types_by_name['ForceReconnectResponse'] = _FORCERECONNECTRESPONSE
+DESCRIPTOR.message_types_by_name['ForceReconnectMetadata'] = _FORCERECONNECTMETADATA
 DESCRIPTOR.message_types_by_name['DetectDeviceConfigIdRequest'] = _DETECTDEVICECONFIGIDREQUEST
 DESCRIPTOR.message_types_by_name['DetectDeviceConfigIdResponse'] = _DETECTDEVICECONFIGIDRESPONSE
 DESCRIPTOR.enum_types_by_name['Output'] = _OUTPUT
@@ -810,6 +1366,120 @@
   })
 _sym_db.RegisterMessage(RestartMetadata)
 
+CacheRequest = _reflection.GeneratedProtocolMessageType('CacheRequest', (_message.Message,), {
+
+  'LocalFile' : _reflection.GeneratedProtocolMessageType('LocalFile', (_message.Message,), {
+    'DESCRIPTOR' : _CACHEREQUEST_LOCALFILE,
+    '__module__' : 'chromiumos.test.api.dut_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.CacheRequest.LocalFile)
+    })
+  ,
+
+  'Pipe' : _reflection.GeneratedProtocolMessageType('Pipe', (_message.Message,), {
+    'DESCRIPTOR' : _CACHEREQUEST_PIPE,
+    '__module__' : 'chromiumos.test.api.dut_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.CacheRequest.Pipe)
+    })
+  ,
+
+  'GSFile' : _reflection.GeneratedProtocolMessageType('GSFile', (_message.Message,), {
+    'DESCRIPTOR' : _CACHEREQUEST_GSFILE,
+    '__module__' : 'chromiumos.test.api.dut_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.CacheRequest.GSFile)
+    })
+  ,
+
+  'GSZipFile' : _reflection.GeneratedProtocolMessageType('GSZipFile', (_message.Message,), {
+    'DESCRIPTOR' : _CACHEREQUEST_GSZIPFILE,
+    '__module__' : 'chromiumos.test.api.dut_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.CacheRequest.GSZipFile)
+    })
+  ,
+
+  'GSTARFile' : _reflection.GeneratedProtocolMessageType('GSTARFile', (_message.Message,), {
+    'DESCRIPTOR' : _CACHEREQUEST_GSTARFILE,
+    '__module__' : 'chromiumos.test.api.dut_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.CacheRequest.GSTARFile)
+    })
+  ,
+  'DESCRIPTOR' : _CACHEREQUEST,
+  '__module__' : 'chromiumos.test.api.dut_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.CacheRequest)
+  })
+_sym_db.RegisterMessage(CacheRequest)
+_sym_db.RegisterMessage(CacheRequest.LocalFile)
+_sym_db.RegisterMessage(CacheRequest.Pipe)
+_sym_db.RegisterMessage(CacheRequest.GSFile)
+_sym_db.RegisterMessage(CacheRequest.GSZipFile)
+_sym_db.RegisterMessage(CacheRequest.GSTARFile)
+
+CacheResponse = _reflection.GeneratedProtocolMessageType('CacheResponse', (_message.Message,), {
+
+  'Success' : _reflection.GeneratedProtocolMessageType('Success', (_message.Message,), {
+    'DESCRIPTOR' : _CACHERESPONSE_SUCCESS,
+    '__module__' : 'chromiumos.test.api.dut_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.CacheResponse.Success)
+    })
+  ,
+
+  'Failure' : _reflection.GeneratedProtocolMessageType('Failure', (_message.Message,), {
+    'DESCRIPTOR' : _CACHERESPONSE_FAILURE,
+    '__module__' : 'chromiumos.test.api.dut_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.CacheResponse.Failure)
+    })
+  ,
+  'DESCRIPTOR' : _CACHERESPONSE,
+  '__module__' : 'chromiumos.test.api.dut_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.CacheResponse)
+  })
+_sym_db.RegisterMessage(CacheResponse)
+_sym_db.RegisterMessage(CacheResponse.Success)
+_sym_db.RegisterMessage(CacheResponse.Failure)
+
+CacheMetadata = _reflection.GeneratedProtocolMessageType('CacheMetadata', (_message.Message,), {
+  'DESCRIPTOR' : _CACHEMETADATA,
+  '__module__' : 'chromiumos.test.api.dut_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.CacheMetadata)
+  })
+_sym_db.RegisterMessage(CacheMetadata)
+
+ForceReconnectRequest = _reflection.GeneratedProtocolMessageType('ForceReconnectRequest', (_message.Message,), {
+  'DESCRIPTOR' : _FORCERECONNECTREQUEST,
+  '__module__' : 'chromiumos.test.api.dut_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.ForceReconnectRequest)
+  })
+_sym_db.RegisterMessage(ForceReconnectRequest)
+
+ForceReconnectResponse = _reflection.GeneratedProtocolMessageType('ForceReconnectResponse', (_message.Message,), {
+
+  'Success' : _reflection.GeneratedProtocolMessageType('Success', (_message.Message,), {
+    'DESCRIPTOR' : _FORCERECONNECTRESPONSE_SUCCESS,
+    '__module__' : 'chromiumos.test.api.dut_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.ForceReconnectResponse.Success)
+    })
+  ,
+
+  'Failure' : _reflection.GeneratedProtocolMessageType('Failure', (_message.Message,), {
+    'DESCRIPTOR' : _FORCERECONNECTRESPONSE_FAILURE,
+    '__module__' : 'chromiumos.test.api.dut_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.ForceReconnectResponse.Failure)
+    })
+  ,
+  'DESCRIPTOR' : _FORCERECONNECTRESPONSE,
+  '__module__' : 'chromiumos.test.api.dut_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.ForceReconnectResponse)
+  })
+_sym_db.RegisterMessage(ForceReconnectResponse)
+_sym_db.RegisterMessage(ForceReconnectResponse.Success)
+_sym_db.RegisterMessage(ForceReconnectResponse.Failure)
+
+ForceReconnectMetadata = _reflection.GeneratedProtocolMessageType('ForceReconnectMetadata', (_message.Message,), {
+  'DESCRIPTOR' : _FORCERECONNECTMETADATA,
+  '__module__' : 'chromiumos.test.api.dut_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.ForceReconnectMetadata)
+  })
+_sym_db.RegisterMessage(ForceReconnectMetadata)
+
 DetectDeviceConfigIdRequest = _reflection.GeneratedProtocolMessageType('DetectDeviceConfigIdRequest', (_message.Message,), {
   'DESCRIPTOR' : _DETECTDEVICECONFIGIDREQUEST,
   '__module__' : 'chromiumos.test.api.dut_service_pb2'
@@ -850,8 +1520,8 @@
   index=0,
   serialized_options=None,
   create_key=_descriptor._internal_create_key,
-  serialized_start=1519,
-  serialized_end=1983,
+  serialized_start=2541,
+  serialized_end=3270,
   methods=[
   _descriptor.MethodDescriptor(
     name='ExecCommand',
@@ -893,6 +1563,26 @@
     serialized_options=None,
     create_key=_descriptor._internal_create_key,
   ),
+  _descriptor.MethodDescriptor(
+    name='Cache',
+    full_name='chromiumos.test.api.DutService.Cache',
+    index=4,
+    containing_service=None,
+    input_type=_CACHEREQUEST,
+    output_type=chromiumos_dot_longrunning_dot_operations__pb2._OPERATION,
+    serialized_options=b'\322A\036\n\rCacheResponse\022\rCacheMetadata',
+    create_key=_descriptor._internal_create_key,
+  ),
+  _descriptor.MethodDescriptor(
+    name='ForceReconnect',
+    full_name='chromiumos.test.api.DutService.ForceReconnect',
+    index=5,
+    containing_service=None,
+    input_type=_FORCERECONNECTREQUEST,
+    output_type=chromiumos_dot_longrunning_dot_operations__pb2._OPERATION,
+    serialized_options=b'\322A0\n\026ForceReconnectResponse\022\026ForceReconnectMetadata',
+    create_key=_descriptor._internal_create_key,
+  ),
 ])
 _sym_db.RegisterServiceDescriptor(_DUTSERVICE)
 
diff --git a/api/gen/chromiumos/test/api/plan_pb2.py b/api/gen/chromiumos/test/api/plan_pb2.py
index 617464c..52e06f8 100644
--- a/api/gen/chromiumos/test/api/plan_pb2.py
+++ b/api/gen/chromiumos/test/api/plan_pb2.py
@@ -20,7 +20,7 @@
   syntax='proto3',
   serialized_options=b'Z-go.chromium.org/chromiumos/config/go/test/api',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n\x1e\x63hromiumos/test/api/plan.proto\x12\x13\x63hromiumos.test.api\x1a\'chromiumos/test/api/coverage_rule.proto\"\x9c\x01\n\nHWTestPlan\x12\x36\n\x02id\x18\x01 \x01(\x0b\x32*.chromiumos.test.api.HWTestPlan.TestPlanId\x12\x39\n\x0e\x63overage_rules\x18\x02 \x03(\x0b\x32!.chromiumos.test.api.CoverageRule\x1a\x1b\n\nTestPlanId\x12\r\n\x05value\x18\x01 \x01(\tB/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
+  serialized_pb=b'\n\x1e\x63hromiumos/test/api/plan.proto\x12\x13\x63hromiumos.test.api\x1a\'chromiumos/test/api/coverage_rule.proto\"\xa0\x01\n\nHWTestPlan\x12\x36\n\x02id\x18\x01 \x01(\x0b\x32*.chromiumos.test.api.HWTestPlan.TestPlanId\x12\x39\n\x0e\x63overage_rules\x18\x02 \x03(\x0b\x32!.chromiumos.test.api.CoverageRule\x1a\x1b\n\nTestPlanId\x12\r\n\x05value\x18\x01 \x01(\t:\x02\x18\x01\x42/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
   ,
   dependencies=[chromiumos_dot_test_dot_api_dot_coverage__rule__pb2.DESCRIPTOR,])
 
@@ -86,14 +86,14 @@
   nested_types=[_HWTESTPLAN_TESTPLANID, ],
   enum_types=[
   ],
-  serialized_options=None,
+  serialized_options=b'\030\001',
   is_extendable=False,
   syntax='proto3',
   extension_ranges=[],
   oneofs=[
   ],
   serialized_start=97,
-  serialized_end=253,
+  serialized_end=257,
 )
 
 _HWTESTPLAN_TESTPLANID.containing_type = _HWTESTPLAN
@@ -119,4 +119,5 @@
 
 
 DESCRIPTOR._options = None
+_HWTESTPLAN._options = None
 # @@protoc_insertion_point(module_scope)
diff --git a/api/gen/chromiumos/test/api/provision_service_pb2.py b/api/gen/chromiumos/test/api/provision_service_pb2.py
index 6400210..e9231b0 100644
--- a/api/gen/chromiumos/test/api/provision_service_pb2.py
+++ b/api/gen/chromiumos/test/api/provision_service_pb2.py
@@ -22,7 +22,7 @@
   syntax='proto3',
   serialized_options=b'Z-go.chromium.org/chromiumos/config/go/test/api',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n+chromiumos/test/api/provision_service.proto\x12\x13\x63hromiumos.test.api\x1a*chromiumos/build/api/firmware_config.proto\x1a\'chromiumos/longrunning/operations.proto\x1a\x1d\x63hromiumos/storage_path.proto\"\x10\n\x0eInstallSuccess\"\xaf\x02\n\x0eInstallFailure\x12:\n\x06reason\x18\x01 \x01(\x0e\x32*.chromiumos.test.api.InstallFailure.Reason\"\xe0\x01\n\x06Reason\x12\x1a\n\x16REASON_INVALID_REQUEST\x10\x00\x12(\n$REASON_DUT_UNREACHABLE_PRE_PROVISION\x10\x01\x12#\n\x1fREASON_DOWNLOADING_IMAGE_FAILED\x10\x02\x12 \n\x1cREASON_PROVISIONING_TIMEDOUT\x10\x03\x12\x1e\n\x1aREASON_PROVISIONING_FAILED\x10\x04\x12)\n%REASON_DUT_UNREACHABLE_POST_PROVISION\x10\x05\"\x88\x02\n\x12InstallCrosRequest\x12\x30\n\x0f\x63ros_image_path\x18\x01 \x01(\x0b\x32\x17.chromiumos.StoragePath\x12\x42\n\tdlc_specs\x18\x02 \x03(\x0b\x32/.chromiumos.test.api.InstallCrosRequest.DLCSpec\x12\x19\n\x11preserve_stateful\x18\x03 \x01(\x08\x12\x16\n\x0eprevent_reboot\x18\x04 \x01(\x08\x12\x32\n\x11overwrite_payload\x18\x05 \x01(\x0b\x32\x17.chromiumos.StoragePath\x1a\x15\n\x07\x44LCSpec\x12\n\n\x02id\x18\x01 \x01(\t\"\x90\x01\n\x13InstallCrosResponse\x12\x36\n\x07success\x18\x01 \x01(\x0b\x32#.chromiumos.test.api.InstallSuccessH\x00\x12\x36\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32#.chromiumos.test.api.InstallFailureH\x00\x42\t\n\x07outcome\"\x15\n\x13InstallCrosMetadata\"J\n\x14InstallLacrosRequest\x12\x32\n\x11lacros_image_path\x18\x01 \x01(\x0b\x32\x17.chromiumos.StoragePath\"\x92\x01\n\x15InstallLacrosResponse\x12\x36\n\x07success\x18\x01 \x01(\x0b\x32#.chromiumos.test.api.InstallSuccessH\x00\x12\x36\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32#.chromiumos.test.api.InstallFailureH\x00\x42\t\n\x07outcome\"\x17\n\x15InstallLacrosMetadata\"D\n\x11InstallAshRequest\x12/\n\x0e\x61sh_image_path\x18\x01 \x01(\x0b\x32\x17.chromiumos.StoragePath\"\x8f\x01\n\x12InstallAshResponse\x12\x36\n\x07success\x18\x01 \x01(\x0b\x32#.chromiumos.test.api.InstallSuccessH\x00\x12\x36\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32#.chromiumos.test.api.InstallFailureH\x00\x42\t\n\x07outcome\"\x14\n\x12InstallAshMetadata\"D\n\x11InstallArcRequest\x12/\n\x0e\x61sh_image_path\x18\x01 \x01(\x0b\x32\x17.chromiumos.StoragePath\"\x8f\x01\n\x12InstallArcResponse\x12\x36\n\x07success\x18\x01 \x01(\x0b\x32#.chromiumos.test.api.InstallSuccessH\x00\x12\x36\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32#.chromiumos.test.api.InstallFailureH\x00\x42\t\n\x07outcome\"\x14\n\x12InstallArcMetadata\"W\n\x16InstallFirmwareRequest\x12=\n\x0f\x66irmware_config\x18\x01 \x01(\x0b\x32$.chromiumos.build.api.FirmwareConfig\"\x94\x01\n\x17InstallFirmwareResponse\x12\x36\n\x07success\x18\x01 \x01(\x0b\x32#.chromiumos.test.api.InstallSuccessH\x00\x12\x36\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32#.chromiumos.test.api.InstallFailureH\x00\x42\t\n\x07outcome\"\x19\n\x17InstallFirmwareMetadata2\xd9\x05\n\x10ProvisionService\x12\x88\x01\n\x0bInstallCros\x12\'.chromiumos.test.api.InstallCrosRequest\x1a!.chromiumos.longrunning.Operation\"-\xd2\x41*\n\x13InstallCrosResponse\x12\x13InstallCrosMetadata\x12\x90\x01\n\rInstallLacros\x12).chromiumos.test.api.InstallLacrosRequest\x1a!.chromiumos.longrunning.Operation\"1\xd2\x41.\n\x15InstallLacrosResponse\x12\x15InstallLacrosMetadata\x12\x84\x01\n\nInstallAsh\x12&.chromiumos.test.api.InstallAshRequest\x1a!.chromiumos.longrunning.Operation\"+\xd2\x41(\n\x12InstallAshResponse\x12\x12InstallAshMetadata\x12\x84\x01\n\nInstallArc\x12&.chromiumos.test.api.InstallArcRequest\x1a!.chromiumos.longrunning.Operation\"+\xd2\x41(\n\x12InstallArcResponse\x12\x12InstallArcMetadata\x12\x98\x01\n\x0fInstallFirmware\x12+.chromiumos.test.api.InstallFirmwareRequest\x1a!.chromiumos.longrunning.Operation\"5\xd2\x41\x32\n\x17InstallFirmwareResponse\x12\x17InstallFirmwareMetadataB/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
+  serialized_pb=b'\n+chromiumos/test/api/provision_service.proto\x12\x13\x63hromiumos.test.api\x1a*chromiumos/build/api/firmware_config.proto\x1a\'chromiumos/longrunning/operations.proto\x1a\x1d\x63hromiumos/storage_path.proto\"\x10\n\x0eInstallSuccess\"\xaf\x02\n\x0eInstallFailure\x12:\n\x06reason\x18\x01 \x01(\x0e\x32*.chromiumos.test.api.InstallFailure.Reason\"\xe0\x01\n\x06Reason\x12\x1a\n\x16REASON_INVALID_REQUEST\x10\x00\x12(\n$REASON_DUT_UNREACHABLE_PRE_PROVISION\x10\x01\x12#\n\x1fREASON_DOWNLOADING_IMAGE_FAILED\x10\x02\x12 \n\x1cREASON_PROVISIONING_TIMEDOUT\x10\x03\x12\x1e\n\x1aREASON_PROVISIONING_FAILED\x10\x04\x12)\n%REASON_DUT_UNREACHABLE_POST_PROVISION\x10\x05\"\x88\x02\n\x12InstallCrosRequest\x12\x30\n\x0f\x63ros_image_path\x18\x01 \x01(\x0b\x32\x17.chromiumos.StoragePath\x12\x42\n\tdlc_specs\x18\x02 \x03(\x0b\x32/.chromiumos.test.api.InstallCrosRequest.DLCSpec\x12\x19\n\x11preserve_stateful\x18\x03 \x01(\x08\x12\x16\n\x0eprevent_reboot\x18\x04 \x01(\x08\x12\x32\n\x11overwrite_payload\x18\x05 \x01(\x0b\x32\x17.chromiumos.StoragePath\x1a\x15\n\x07\x44LCSpec\x12\n\n\x02id\x18\x01 \x01(\t\"\x90\x01\n\x13InstallCrosResponse\x12\x36\n\x07success\x18\x01 \x01(\x0b\x32#.chromiumos.test.api.InstallSuccessH\x00\x12\x36\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32#.chromiumos.test.api.InstallFailureH\x00\x42\t\n\x07outcome\"\x15\n\x13InstallCrosMetadata\"J\n\x14InstallLacrosRequest\x12\x32\n\x11lacros_image_path\x18\x01 \x01(\x0b\x32\x17.chromiumos.StoragePath\"\x92\x01\n\x15InstallLacrosResponse\x12\x36\n\x07success\x18\x01 \x01(\x0b\x32#.chromiumos.test.api.InstallSuccessH\x00\x12\x36\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32#.chromiumos.test.api.InstallFailureH\x00\x42\t\n\x07outcome\"\x17\n\x15InstallLacrosMetadata\"D\n\x11InstallAshRequest\x12/\n\x0e\x61sh_image_path\x18\x01 \x01(\x0b\x32\x17.chromiumos.StoragePath\"\x8f\x01\n\x12InstallAshResponse\x12\x36\n\x07success\x18\x01 \x01(\x0b\x32#.chromiumos.test.api.InstallSuccessH\x00\x12\x36\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32#.chromiumos.test.api.InstallFailureH\x00\x42\t\n\x07outcome\"\x14\n\x12InstallAshMetadata\"D\n\x11InstallArcRequest\x12/\n\x0e\x61sh_image_path\x18\x01 \x01(\x0b\x32\x17.chromiumos.StoragePath\"\x8f\x01\n\x12InstallArcResponse\x12\x36\n\x07success\x18\x01 \x01(\x0b\x32#.chromiumos.test.api.InstallSuccessH\x00\x12\x36\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32#.chromiumos.test.api.InstallFailureH\x00\x42\t\n\x07outcome\"\x14\n\x12InstallArcMetadata\"y\n\x16InstallFirmwareRequest\x12=\n\x0f\x66irmware_config\x18\x01 \x01(\x0b\x32$.chromiumos.build.api.FirmwareConfig\x12\r\n\x05\x66orce\x18\x08 \x01(\x08\x12\x11\n\tuse_servo\x18\t \x01(\x08\"\x94\x01\n\x17InstallFirmwareResponse\x12\x36\n\x07success\x18\x01 \x01(\x0b\x32#.chromiumos.test.api.InstallSuccessH\x00\x12\x36\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32#.chromiumos.test.api.InstallFailureH\x00\x42\t\n\x07outcome\"\x19\n\x17InstallFirmwareMetadata2\xd9\x05\n\x10ProvisionService\x12\x88\x01\n\x0bInstallCros\x12\'.chromiumos.test.api.InstallCrosRequest\x1a!.chromiumos.longrunning.Operation\"-\xd2\x41*\n\x13InstallCrosResponse\x12\x13InstallCrosMetadata\x12\x90\x01\n\rInstallLacros\x12).chromiumos.test.api.InstallLacrosRequest\x1a!.chromiumos.longrunning.Operation\"1\xd2\x41.\n\x15InstallLacrosResponse\x12\x15InstallLacrosMetadata\x12\x84\x01\n\nInstallAsh\x12&.chromiumos.test.api.InstallAshRequest\x1a!.chromiumos.longrunning.Operation\"+\xd2\x41(\n\x12InstallAshResponse\x12\x12InstallAshMetadata\x12\x84\x01\n\nInstallArc\x12&.chromiumos.test.api.InstallArcRequest\x1a!.chromiumos.longrunning.Operation\"+\xd2\x41(\n\x12InstallArcResponse\x12\x12InstallArcMetadata\x12\x98\x01\n\x0fInstallFirmware\x12+.chromiumos.test.api.InstallFirmwareRequest\x1a!.chromiumos.longrunning.Operation\"5\xd2\x41\x32\n\x17InstallFirmwareResponse\x12\x17InstallFirmwareMetadataB/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
   ,
   dependencies=[chromiumos_dot_build_dot_api_dot_firmware__config__pb2.DESCRIPTOR,chromiumos_dot_longrunning_dot_operations__pb2.DESCRIPTOR,chromiumos_dot_storage__path__pb2.DESCRIPTOR,])
 
@@ -610,6 +610,20 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='force', full_name='chromiumos.test.api.InstallFirmwareRequest.force', index=1,
+      number=8, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='use_servo', full_name='chromiumos.test.api.InstallFirmwareRequest.use_servo', index=2,
+      number=9, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -623,7 +637,7 @@
   oneofs=[
   ],
   serialized_start=1671,
-  serialized_end=1758,
+  serialized_end=1792,
 )
 
 
@@ -666,8 +680,8 @@
       create_key=_descriptor._internal_create_key,
     fields=[]),
   ],
-  serialized_start=1761,
-  serialized_end=1909,
+  serialized_start=1795,
+  serialized_end=1943,
 )
 
 
@@ -691,8 +705,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1911,
-  serialized_end=1936,
+  serialized_start=1945,
+  serialized_end=1970,
 )
 
 _INSTALLFAILURE.fields_by_name['reason'].enum_type = _INSTALLFAILURE_REASON
@@ -901,8 +915,8 @@
   index=0,
   serialized_options=None,
   create_key=_descriptor._internal_create_key,
-  serialized_start=1939,
-  serialized_end=2668,
+  serialized_start=1973,
+  serialized_end=2702,
   methods=[
   _descriptor.MethodDescriptor(
     name='InstallCros',
diff --git a/api/gen/chromiumos/test/api/provision_state_pb2.py b/api/gen/chromiumos/test/api/provision_state_pb2.py
index 380a2dc..6b4cc5d 100644
--- a/api/gen/chromiumos/test/api/provision_state_pb2.py
+++ b/api/gen/chromiumos/test/api/provision_state_pb2.py
@@ -23,7 +23,7 @@
   syntax='proto3',
   serialized_options=b'Z-go.chromium.org/chromiumos/config/go/test/api',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n)chromiumos/test/api/provision_state.proto\x12\x13\x63hromiumos.test.api\x1a\x1e\x63hromiumos/build/api/dlc.proto\x1a*chromiumos/build/api/firmware_config.proto\x1a\"chromiumos/build/api/portage.proto\x1a\x1d\x63hromiumos/storage_path.proto\"\xa9\x04\n\x0eProvisionState\x12\x32\n\x02id\x18\x01 \x01(\x0b\x32&.chromiumos.test.api.ProvisionState.Id\x12\x36\n\x08\x66irmware\x18\x02 \x01(\x0b\x32$.chromiumos.build.api.FirmwareConfig\x12\x45\n\x0csystem_image\x18\x03 \x01(\x0b\x32/.chromiumos.test.api.ProvisionState.SystemImage\x12=\n\x08packages\x18\x04 \x03(\x0b\x32+.chromiumos.test.api.ProvisionState.Package\x12\x16\n\x0eprevent_reboot\x18\x05 \x01(\x08\x1a\x13\n\x02Id\x12\r\n\x05value\x18\x01 \x01(\t\x1a~\n\x0bSystemImage\x12\x0f\n\x07version\x18\x01 \x01(\t\x12\x32\n\x11system_image_path\x18\x02 \x01(\x0b\x32\x17.chromiumos.StoragePath\x12*\n\x04\x64lcs\x18\x03 \x03(\x0b\x32\x1c.chromiumos.build.api.Dlc.Id\x1ax\n\x07Package\x12>\n\x0fportage_package\x18\x01 \x01(\x0b\x32%.chromiumos.build.api.Portage.Package\x12-\n\x0cpackage_path\x18\x02 \x01(\x0b\x32\x17.chromiumos.StoragePath\"\xb4\x01\n\x0fProvisionConfig\x12\x36\n\x08\x66irmware\x18\x01 \x01(\x0b\x32$.chromiumos.build.api.FirmwareConfig\x12*\n\x04\x64lcs\x18\x02 \x03(\x0b\x32\x1c.chromiumos.build.api.Dlc.Id\x12=\n\x08packages\x18\x03 \x03(\x0b\x32+.chromiumos.test.api.ProvisionState.PackageB/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
+  serialized_pb=b'\n)chromiumos/test/api/provision_state.proto\x12\x13\x63hromiumos.test.api\x1a\x1e\x63hromiumos/build/api/dlc.proto\x1a*chromiumos/build/api/firmware_config.proto\x1a\"chromiumos/build/api/portage.proto\x1a\x1d\x63hromiumos/storage_path.proto\"\xde\x04\n\x0eProvisionState\x12\x32\n\x02id\x18\x01 \x01(\x0b\x32&.chromiumos.test.api.ProvisionState.Id\x12\x36\n\x08\x66irmware\x18\x02 \x01(\x0b\x32$.chromiumos.build.api.FirmwareConfig\x12\x45\n\x0csystem_image\x18\x03 \x01(\x0b\x32/.chromiumos.test.api.ProvisionState.SystemImage\x12=\n\x08packages\x18\x04 \x03(\x0b\x32+.chromiumos.test.api.ProvisionState.Package\x12\x16\n\x0eprevent_reboot\x18\x05 \x01(\x08\x1a\x13\n\x02Id\x12\r\n\x05value\x18\x01 \x01(\t\x1a\xb2\x01\n\x0bSystemImage\x12\x0f\n\x07version\x18\x01 \x01(\t\x12\x32\n\x11system_image_path\x18\x02 \x01(\x0b\x32\x17.chromiumos.StoragePath\x12*\n\x04\x64lcs\x18\x03 \x03(\x0b\x32\x1c.chromiumos.build.api.Dlc.Id\x12\x32\n\x11overwrite_payload\x18\x04 \x01(\x0b\x32\x17.chromiumos.StoragePath\x1ax\n\x07Package\x12>\n\x0fportage_package\x18\x01 \x01(\x0b\x32%.chromiumos.build.api.Portage.Package\x12-\n\x0cpackage_path\x18\x02 \x01(\x0b\x32\x17.chromiumos.StoragePath\"\xff\x01\n\x0fProvisionConfig\x12\x36\n\x08\x66irmware\x18\x01 \x01(\x0b\x32$.chromiumos.build.api.FirmwareConfig\x12*\n\x04\x64lcs\x18\x02 \x03(\x0b\x32\x1c.chromiumos.build.api.Dlc.Id\x12=\n\x08packages\x18\x03 \x03(\x0b\x32+.chromiumos.test.api.ProvisionState.Package\x12\x15\n\rboard_variant\x18\x04 \x01(\t\x12\x32\n\x11overwrite_payload\x18\x05 \x01(\x0b\x32\x17.chromiumos.StoragePathB/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
   ,
   dependencies=[chromiumos_dot_build_dot_api_dot_dlc__pb2.DESCRIPTOR,chromiumos_dot_build_dot_api_dot_firmware__config__pb2.DESCRIPTOR,chromiumos_dot_build_dot_api_dot_portage__pb2.DESCRIPTOR,chromiumos_dot_storage__path__pb2.DESCRIPTOR,])
 
@@ -90,6 +90,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='overwrite_payload', full_name='chromiumos.test.api.ProvisionState.SystemImage.overwrite_payload', index=3,
+      number=4, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -102,8 +109,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=515,
-  serialized_end=641,
+  serialized_start=516,
+  serialized_end=694,
 )
 
 _PROVISIONSTATE_PACKAGE = _descriptor.Descriptor(
@@ -140,8 +147,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=643,
-  serialized_end=763,
+  serialized_start=696,
+  serialized_end=816,
 )
 
 _PROVISIONSTATE = _descriptor.Descriptor(
@@ -200,7 +207,7 @@
   oneofs=[
   ],
   serialized_start=210,
-  serialized_end=763,
+  serialized_end=816,
 )
 
 
@@ -233,6 +240,20 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='board_variant', full_name='chromiumos.test.api.ProvisionConfig.board_variant', index=3,
+      number=4, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='overwrite_payload', full_name='chromiumos.test.api.ProvisionConfig.overwrite_payload', index=4,
+      number=5, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -245,13 +266,14 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=766,
-  serialized_end=946,
+  serialized_start=819,
+  serialized_end=1074,
 )
 
 _PROVISIONSTATE_ID.containing_type = _PROVISIONSTATE
 _PROVISIONSTATE_SYSTEMIMAGE.fields_by_name['system_image_path'].message_type = chromiumos_dot_storage__path__pb2._STORAGEPATH
 _PROVISIONSTATE_SYSTEMIMAGE.fields_by_name['dlcs'].message_type = chromiumos_dot_build_dot_api_dot_dlc__pb2._DLC_ID
+_PROVISIONSTATE_SYSTEMIMAGE.fields_by_name['overwrite_payload'].message_type = chromiumos_dot_storage__path__pb2._STORAGEPATH
 _PROVISIONSTATE_SYSTEMIMAGE.containing_type = _PROVISIONSTATE
 _PROVISIONSTATE_PACKAGE.fields_by_name['portage_package'].message_type = chromiumos_dot_build_dot_api_dot_portage__pb2._PORTAGE_PACKAGE
 _PROVISIONSTATE_PACKAGE.fields_by_name['package_path'].message_type = chromiumos_dot_storage__path__pb2._STORAGEPATH
@@ -263,6 +285,7 @@
 _PROVISIONCONFIG.fields_by_name['firmware'].message_type = chromiumos_dot_build_dot_api_dot_firmware__config__pb2._FIRMWARECONFIG
 _PROVISIONCONFIG.fields_by_name['dlcs'].message_type = chromiumos_dot_build_dot_api_dot_dlc__pb2._DLC_ID
 _PROVISIONCONFIG.fields_by_name['packages'].message_type = _PROVISIONSTATE_PACKAGE
+_PROVISIONCONFIG.fields_by_name['overwrite_payload'].message_type = chromiumos_dot_storage__path__pb2._STORAGEPATH
 DESCRIPTOR.message_types_by_name['ProvisionState'] = _PROVISIONSTATE
 DESCRIPTOR.message_types_by_name['ProvisionConfig'] = _PROVISIONCONFIG
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
diff --git a/api/gen/chromiumos/test/api/servod_service_pb2.py b/api/gen/chromiumos/test/api/servod_service_pb2.py
new file mode 100644
index 0000000..3071c21
--- /dev/null
+++ b/api/gen/chromiumos/test/api/servod_service_pb2.py
@@ -0,0 +1,1077 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: chromiumos/test/api/servod_service.proto
+"""Generated protocol buffer code."""
+from chromite.third_party.google.protobuf import descriptor as _descriptor
+from chromite.third_party.google.protobuf import message as _message
+from chromite.third_party.google.protobuf import reflection as _reflection
+from chromite.third_party.google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from chromite.api.gen.chromiumos.config.api.test.xmlrpc import xmlrpc_pb2 as chromiumos_dot_config_dot_api_dot_test_dot_xmlrpc_dot_xmlrpc__pb2
+from chromite.api.gen.chromiumos.longrunning import operations_pb2 as chromiumos_dot_longrunning_dot_operations__pb2
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='chromiumos/test/api/servod_service.proto',
+  package='chromiumos.test.api',
+  syntax='proto3',
+  serialized_options=b'Z-go.chromium.org/chromiumos/config/go/test/api',
+  create_key=_descriptor._internal_create_key,
+  serialized_pb=b'\n(chromiumos/test/api/servod_service.proto\x12\x13\x63hromiumos.test.api\x1a.chromiumos/config/api/test/xmlrpc/xmlrpc.proto\x1a\'chromiumos/longrunning/operations.proto\"\x8a\x02\n\x12StartServodRequest\x12\x17\n\x0fservo_host_path\x18\x01 \x01(\t\x12$\n\x1cservod_docker_container_name\x18\x02 \x01(\t\x12 \n\x18servod_docker_image_path\x18\x03 \x01(\t\x12\x13\n\x0bservod_port\x18\x04 \x01(\x05\x12\r\n\x05\x62oard\x18\x05 \x01(\t\x12\r\n\x05model\x18\x06 \x01(\t\x12\x13\n\x0bserial_name\x18\x07 \x01(\t\x12\r\n\x05\x64\x65\x62ug\x18\x08 \x01(\t\x12\x15\n\rrecovery_mode\x18\t \x01(\t\x12\x0e\n\x06\x63onfig\x18\n \x01(\t\x12\x15\n\rallow_dual_v4\x18\x0b \x01(\t\"\xd6\x01\n\x13StartServodResponse\x12\x43\n\x07success\x18\x01 \x01(\x0b\x32\x30.chromiumos.test.api.StartServodResponse.SuccessH\x00\x12\x43\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32\x30.chromiumos.test.api.StartServodResponse.FailureH\x00\x1a\t\n\x07Success\x1a \n\x07\x46\x61ilure\x12\x15\n\rerror_message\x18\x01 \x01(\tB\x08\n\x06result\"\x15\n\x13StartServodMetadata\"g\n\x11StopServodRequest\x12\x17\n\x0fservo_host_path\x18\x01 \x01(\t\x12$\n\x1cservod_docker_container_name\x18\x02 \x01(\t\x12\x13\n\x0bservod_port\x18\x03 \x01(\x05\"\xd3\x01\n\x12StopServodResponse\x12\x42\n\x07success\x18\x01 \x01(\x0b\x32/.chromiumos.test.api.StopServodResponse.SuccessH\x00\x12\x42\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32/.chromiumos.test.api.StopServodResponse.FailureH\x00\x1a\t\n\x07Success\x1a \n\x07\x46\x61ilure\x12\x15\n\rerror_message\x18\x01 \x01(\tB\x08\n\x06result\"\x14\n\x12StopServodMetadata\"o\n\x0e\x45xecCmdRequest\x12\x17\n\x0fservo_host_path\x18\x01 \x01(\t\x12$\n\x1cservod_docker_container_name\x18\x02 \x01(\t\x12\x0f\n\x07\x63ommand\x18\x03 \x01(\t\x12\r\n\x05stdin\x18\x04 \x01(\x0c\"\xc9\x01\n\x0f\x45xecCmdResponse\x12@\n\texit_info\x18\x01 \x01(\x0b\x32-.chromiumos.test.api.ExecCmdResponse.ExitInfo\x12\x0e\n\x06stdout\x18\x02 \x01(\x0c\x12\x0e\n\x06stderr\x18\x03 \x01(\x0c\x1aT\n\x08\x45xitInfo\x12\x0e\n\x06status\x18\x01 \x01(\x05\x12\x10\n\x08signaled\x18\x02 \x01(\x08\x12\x0f\n\x07started\x18\x03 \x01(\x08\x12\x15\n\rerror_message\x18\x04 \x01(\t\"\x11\n\x0f\x45xecCmdMetadata\"\x8f\x02\n\x11\x43\x61llServodRequest\x12\x17\n\x0fservo_host_path\x18\x01 \x01(\t\x12$\n\x1cservod_docker_container_name\x18\x02 \x01(\t\x12\x13\n\x0bservod_port\x18\x03 \x01(\x05\x12=\n\x06method\x18\x04 \x01(\x0e\x32-.chromiumos.test.api.CallServodRequest.Method\x12\x36\n\x04\x61rgs\x18\x05 \x03(\x0b\x32(.chromiumos.config.api.test.xmlrpc.Value\"/\n\x06Method\x12\x07\n\x03\x44OC\x10\x00\x12\x07\n\x03GET\x10\x01\x12\x07\n\x03SET\x10\x02\x12\n\n\x06HWINIT\x10\x03\"\x8d\x02\n\x12\x43\x61llServodResponse\x12\x42\n\x07success\x18\x01 \x01(\x0b\x32/.chromiumos.test.api.CallServodResponse.SuccessH\x00\x12\x42\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32/.chromiumos.test.api.CallServodResponse.FailureH\x00\x1a\x43\n\x07Success\x12\x38\n\x06result\x18\x01 \x01(\x0b\x32(.chromiumos.config.api.test.xmlrpc.Value\x1a \n\x07\x46\x61ilure\x12\x15\n\rerror_message\x18\x01 \x01(\tB\x08\n\x06result\"\x14\n\x12\x43\x61llServodMetadata2\xd6\x03\n\rServodService\x12\x88\x01\n\x0bStartServod\x12\'.chromiumos.test.api.StartServodRequest\x1a!.chromiumos.longrunning.Operation\"-\xd2\x41*\n\x13StartServodResponse\x12\x13StartServodMetadata\x12\x84\x01\n\nStopServod\x12&.chromiumos.test.api.StopServodRequest\x1a!.chromiumos.longrunning.Operation\"+\xd2\x41(\n\x12StopServodResponse\x12\x12StopServodMetadata\x12T\n\x07\x45xecCmd\x12#.chromiumos.test.api.ExecCmdRequest\x1a$.chromiumos.test.api.ExecCmdResponse\x12]\n\nCallServod\x12&.chromiumos.test.api.CallServodRequest\x1a\'.chromiumos.test.api.CallServodResponseB/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
+  ,
+  dependencies=[chromiumos_dot_config_dot_api_dot_test_dot_xmlrpc_dot_xmlrpc__pb2.DESCRIPTOR,chromiumos_dot_longrunning_dot_operations__pb2.DESCRIPTOR,])
+
+
+
+_CALLSERVODREQUEST_METHOD = _descriptor.EnumDescriptor(
+  name='Method',
+  full_name='chromiumos.test.api.CallServodRequest.Method',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='DOC', index=0, number=0,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='GET', index=1, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='SET', index=2, number=2,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='HWINIT', index=3, number=3,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=1565,
+  serialized_end=1612,
+)
+_sym_db.RegisterEnumDescriptor(_CALLSERVODREQUEST_METHOD)
+
+
+_STARTSERVODREQUEST = _descriptor.Descriptor(
+  name='StartServodRequest',
+  full_name='chromiumos.test.api.StartServodRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='servo_host_path', full_name='chromiumos.test.api.StartServodRequest.servo_host_path', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='servod_docker_container_name', full_name='chromiumos.test.api.StartServodRequest.servod_docker_container_name', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='servod_docker_image_path', full_name='chromiumos.test.api.StartServodRequest.servod_docker_image_path', index=2,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='servod_port', full_name='chromiumos.test.api.StartServodRequest.servod_port', index=3,
+      number=4, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='board', full_name='chromiumos.test.api.StartServodRequest.board', index=4,
+      number=5, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='model', full_name='chromiumos.test.api.StartServodRequest.model', index=5,
+      number=6, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='serial_name', full_name='chromiumos.test.api.StartServodRequest.serial_name', index=6,
+      number=7, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='debug', full_name='chromiumos.test.api.StartServodRequest.debug', index=7,
+      number=8, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='recovery_mode', full_name='chromiumos.test.api.StartServodRequest.recovery_mode', index=8,
+      number=9, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='config', full_name='chromiumos.test.api.StartServodRequest.config', index=9,
+      number=10, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='allow_dual_v4', full_name='chromiumos.test.api.StartServodRequest.allow_dual_v4', index=10,
+      number=11, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=155,
+  serialized_end=421,
+)
+
+
+_STARTSERVODRESPONSE_SUCCESS = _descriptor.Descriptor(
+  name='Success',
+  full_name='chromiumos.test.api.StartServodResponse.Success',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=585,
+  serialized_end=594,
+)
+
+_STARTSERVODRESPONSE_FAILURE = _descriptor.Descriptor(
+  name='Failure',
+  full_name='chromiumos.test.api.StartServodResponse.Failure',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='error_message', full_name='chromiumos.test.api.StartServodResponse.Failure.error_message', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=596,
+  serialized_end=628,
+)
+
+_STARTSERVODRESPONSE = _descriptor.Descriptor(
+  name='StartServodResponse',
+  full_name='chromiumos.test.api.StartServodResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='success', full_name='chromiumos.test.api.StartServodResponse.success', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='failure', full_name='chromiumos.test.api.StartServodResponse.failure', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[_STARTSERVODRESPONSE_SUCCESS, _STARTSERVODRESPONSE_FAILURE, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+    _descriptor.OneofDescriptor(
+      name='result', full_name='chromiumos.test.api.StartServodResponse.result',
+      index=0, containing_type=None,
+      create_key=_descriptor._internal_create_key,
+    fields=[]),
+  ],
+  serialized_start=424,
+  serialized_end=638,
+)
+
+
+_STARTSERVODMETADATA = _descriptor.Descriptor(
+  name='StartServodMetadata',
+  full_name='chromiumos.test.api.StartServodMetadata',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=640,
+  serialized_end=661,
+)
+
+
+_STOPSERVODREQUEST = _descriptor.Descriptor(
+  name='StopServodRequest',
+  full_name='chromiumos.test.api.StopServodRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='servo_host_path', full_name='chromiumos.test.api.StopServodRequest.servo_host_path', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='servod_docker_container_name', full_name='chromiumos.test.api.StopServodRequest.servod_docker_container_name', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='servod_port', full_name='chromiumos.test.api.StopServodRequest.servod_port', index=2,
+      number=3, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=663,
+  serialized_end=766,
+)
+
+
+_STOPSERVODRESPONSE_SUCCESS = _descriptor.Descriptor(
+  name='Success',
+  full_name='chromiumos.test.api.StopServodResponse.Success',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=585,
+  serialized_end=594,
+)
+
+_STOPSERVODRESPONSE_FAILURE = _descriptor.Descriptor(
+  name='Failure',
+  full_name='chromiumos.test.api.StopServodResponse.Failure',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='error_message', full_name='chromiumos.test.api.StopServodResponse.Failure.error_message', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=596,
+  serialized_end=628,
+)
+
+_STOPSERVODRESPONSE = _descriptor.Descriptor(
+  name='StopServodResponse',
+  full_name='chromiumos.test.api.StopServodResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='success', full_name='chromiumos.test.api.StopServodResponse.success', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='failure', full_name='chromiumos.test.api.StopServodResponse.failure', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[_STOPSERVODRESPONSE_SUCCESS, _STOPSERVODRESPONSE_FAILURE, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+    _descriptor.OneofDescriptor(
+      name='result', full_name='chromiumos.test.api.StopServodResponse.result',
+      index=0, containing_type=None,
+      create_key=_descriptor._internal_create_key,
+    fields=[]),
+  ],
+  serialized_start=769,
+  serialized_end=980,
+)
+
+
+_STOPSERVODMETADATA = _descriptor.Descriptor(
+  name='StopServodMetadata',
+  full_name='chromiumos.test.api.StopServodMetadata',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=982,
+  serialized_end=1002,
+)
+
+
+_EXECCMDREQUEST = _descriptor.Descriptor(
+  name='ExecCmdRequest',
+  full_name='chromiumos.test.api.ExecCmdRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='servo_host_path', full_name='chromiumos.test.api.ExecCmdRequest.servo_host_path', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='servod_docker_container_name', full_name='chromiumos.test.api.ExecCmdRequest.servod_docker_container_name', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='command', full_name='chromiumos.test.api.ExecCmdRequest.command', index=2,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='stdin', full_name='chromiumos.test.api.ExecCmdRequest.stdin', index=3,
+      number=4, type=12, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"",
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1004,
+  serialized_end=1115,
+)
+
+
+_EXECCMDRESPONSE_EXITINFO = _descriptor.Descriptor(
+  name='ExitInfo',
+  full_name='chromiumos.test.api.ExecCmdResponse.ExitInfo',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='status', full_name='chromiumos.test.api.ExecCmdResponse.ExitInfo.status', index=0,
+      number=1, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='signaled', full_name='chromiumos.test.api.ExecCmdResponse.ExitInfo.signaled', index=1,
+      number=2, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='started', full_name='chromiumos.test.api.ExecCmdResponse.ExitInfo.started', index=2,
+      number=3, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='error_message', full_name='chromiumos.test.api.ExecCmdResponse.ExitInfo.error_message', index=3,
+      number=4, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1235,
+  serialized_end=1319,
+)
+
+_EXECCMDRESPONSE = _descriptor.Descriptor(
+  name='ExecCmdResponse',
+  full_name='chromiumos.test.api.ExecCmdResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='exit_info', full_name='chromiumos.test.api.ExecCmdResponse.exit_info', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='stdout', full_name='chromiumos.test.api.ExecCmdResponse.stdout', index=1,
+      number=2, type=12, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"",
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='stderr', full_name='chromiumos.test.api.ExecCmdResponse.stderr', index=2,
+      number=3, type=12, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"",
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[_EXECCMDRESPONSE_EXITINFO, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1118,
+  serialized_end=1319,
+)
+
+
+_EXECCMDMETADATA = _descriptor.Descriptor(
+  name='ExecCmdMetadata',
+  full_name='chromiumos.test.api.ExecCmdMetadata',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1321,
+  serialized_end=1338,
+)
+
+
+_CALLSERVODREQUEST = _descriptor.Descriptor(
+  name='CallServodRequest',
+  full_name='chromiumos.test.api.CallServodRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='servo_host_path', full_name='chromiumos.test.api.CallServodRequest.servo_host_path', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='servod_docker_container_name', full_name='chromiumos.test.api.CallServodRequest.servod_docker_container_name', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='servod_port', full_name='chromiumos.test.api.CallServodRequest.servod_port', index=2,
+      number=3, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='method', full_name='chromiumos.test.api.CallServodRequest.method', index=3,
+      number=4, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='args', full_name='chromiumos.test.api.CallServodRequest.args', index=4,
+      number=5, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+    _CALLSERVODREQUEST_METHOD,
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1341,
+  serialized_end=1612,
+)
+
+
+_CALLSERVODRESPONSE_SUCCESS = _descriptor.Descriptor(
+  name='Success',
+  full_name='chromiumos.test.api.CallServodResponse.Success',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='result', full_name='chromiumos.test.api.CallServodResponse.Success.result', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1773,
+  serialized_end=1840,
+)
+
+_CALLSERVODRESPONSE_FAILURE = _descriptor.Descriptor(
+  name='Failure',
+  full_name='chromiumos.test.api.CallServodResponse.Failure',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='error_message', full_name='chromiumos.test.api.CallServodResponse.Failure.error_message', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=596,
+  serialized_end=628,
+)
+
+_CALLSERVODRESPONSE = _descriptor.Descriptor(
+  name='CallServodResponse',
+  full_name='chromiumos.test.api.CallServodResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='success', full_name='chromiumos.test.api.CallServodResponse.success', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='failure', full_name='chromiumos.test.api.CallServodResponse.failure', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[_CALLSERVODRESPONSE_SUCCESS, _CALLSERVODRESPONSE_FAILURE, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+    _descriptor.OneofDescriptor(
+      name='result', full_name='chromiumos.test.api.CallServodResponse.result',
+      index=0, containing_type=None,
+      create_key=_descriptor._internal_create_key,
+    fields=[]),
+  ],
+  serialized_start=1615,
+  serialized_end=1884,
+)
+
+
+_CALLSERVODMETADATA = _descriptor.Descriptor(
+  name='CallServodMetadata',
+  full_name='chromiumos.test.api.CallServodMetadata',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1886,
+  serialized_end=1906,
+)
+
+_STARTSERVODRESPONSE_SUCCESS.containing_type = _STARTSERVODRESPONSE
+_STARTSERVODRESPONSE_FAILURE.containing_type = _STARTSERVODRESPONSE
+_STARTSERVODRESPONSE.fields_by_name['success'].message_type = _STARTSERVODRESPONSE_SUCCESS
+_STARTSERVODRESPONSE.fields_by_name['failure'].message_type = _STARTSERVODRESPONSE_FAILURE
+_STARTSERVODRESPONSE.oneofs_by_name['result'].fields.append(
+  _STARTSERVODRESPONSE.fields_by_name['success'])
+_STARTSERVODRESPONSE.fields_by_name['success'].containing_oneof = _STARTSERVODRESPONSE.oneofs_by_name['result']
+_STARTSERVODRESPONSE.oneofs_by_name['result'].fields.append(
+  _STARTSERVODRESPONSE.fields_by_name['failure'])
+_STARTSERVODRESPONSE.fields_by_name['failure'].containing_oneof = _STARTSERVODRESPONSE.oneofs_by_name['result']
+_STOPSERVODRESPONSE_SUCCESS.containing_type = _STOPSERVODRESPONSE
+_STOPSERVODRESPONSE_FAILURE.containing_type = _STOPSERVODRESPONSE
+_STOPSERVODRESPONSE.fields_by_name['success'].message_type = _STOPSERVODRESPONSE_SUCCESS
+_STOPSERVODRESPONSE.fields_by_name['failure'].message_type = _STOPSERVODRESPONSE_FAILURE
+_STOPSERVODRESPONSE.oneofs_by_name['result'].fields.append(
+  _STOPSERVODRESPONSE.fields_by_name['success'])
+_STOPSERVODRESPONSE.fields_by_name['success'].containing_oneof = _STOPSERVODRESPONSE.oneofs_by_name['result']
+_STOPSERVODRESPONSE.oneofs_by_name['result'].fields.append(
+  _STOPSERVODRESPONSE.fields_by_name['failure'])
+_STOPSERVODRESPONSE.fields_by_name['failure'].containing_oneof = _STOPSERVODRESPONSE.oneofs_by_name['result']
+_EXECCMDRESPONSE_EXITINFO.containing_type = _EXECCMDRESPONSE
+_EXECCMDRESPONSE.fields_by_name['exit_info'].message_type = _EXECCMDRESPONSE_EXITINFO
+_CALLSERVODREQUEST.fields_by_name['method'].enum_type = _CALLSERVODREQUEST_METHOD
+_CALLSERVODREQUEST.fields_by_name['args'].message_type = chromiumos_dot_config_dot_api_dot_test_dot_xmlrpc_dot_xmlrpc__pb2._VALUE
+_CALLSERVODREQUEST_METHOD.containing_type = _CALLSERVODREQUEST
+_CALLSERVODRESPONSE_SUCCESS.fields_by_name['result'].message_type = chromiumos_dot_config_dot_api_dot_test_dot_xmlrpc_dot_xmlrpc__pb2._VALUE
+_CALLSERVODRESPONSE_SUCCESS.containing_type = _CALLSERVODRESPONSE
+_CALLSERVODRESPONSE_FAILURE.containing_type = _CALLSERVODRESPONSE
+_CALLSERVODRESPONSE.fields_by_name['success'].message_type = _CALLSERVODRESPONSE_SUCCESS
+_CALLSERVODRESPONSE.fields_by_name['failure'].message_type = _CALLSERVODRESPONSE_FAILURE
+_CALLSERVODRESPONSE.oneofs_by_name['result'].fields.append(
+  _CALLSERVODRESPONSE.fields_by_name['success'])
+_CALLSERVODRESPONSE.fields_by_name['success'].containing_oneof = _CALLSERVODRESPONSE.oneofs_by_name['result']
+_CALLSERVODRESPONSE.oneofs_by_name['result'].fields.append(
+  _CALLSERVODRESPONSE.fields_by_name['failure'])
+_CALLSERVODRESPONSE.fields_by_name['failure'].containing_oneof = _CALLSERVODRESPONSE.oneofs_by_name['result']
+DESCRIPTOR.message_types_by_name['StartServodRequest'] = _STARTSERVODREQUEST
+DESCRIPTOR.message_types_by_name['StartServodResponse'] = _STARTSERVODRESPONSE
+DESCRIPTOR.message_types_by_name['StartServodMetadata'] = _STARTSERVODMETADATA
+DESCRIPTOR.message_types_by_name['StopServodRequest'] = _STOPSERVODREQUEST
+DESCRIPTOR.message_types_by_name['StopServodResponse'] = _STOPSERVODRESPONSE
+DESCRIPTOR.message_types_by_name['StopServodMetadata'] = _STOPSERVODMETADATA
+DESCRIPTOR.message_types_by_name['ExecCmdRequest'] = _EXECCMDREQUEST
+DESCRIPTOR.message_types_by_name['ExecCmdResponse'] = _EXECCMDRESPONSE
+DESCRIPTOR.message_types_by_name['ExecCmdMetadata'] = _EXECCMDMETADATA
+DESCRIPTOR.message_types_by_name['CallServodRequest'] = _CALLSERVODREQUEST
+DESCRIPTOR.message_types_by_name['CallServodResponse'] = _CALLSERVODRESPONSE
+DESCRIPTOR.message_types_by_name['CallServodMetadata'] = _CALLSERVODMETADATA
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+StartServodRequest = _reflection.GeneratedProtocolMessageType('StartServodRequest', (_message.Message,), {
+  'DESCRIPTOR' : _STARTSERVODREQUEST,
+  '__module__' : 'chromiumos.test.api.servod_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.StartServodRequest)
+  })
+_sym_db.RegisterMessage(StartServodRequest)
+
+StartServodResponse = _reflection.GeneratedProtocolMessageType('StartServodResponse', (_message.Message,), {
+
+  'Success' : _reflection.GeneratedProtocolMessageType('Success', (_message.Message,), {
+    'DESCRIPTOR' : _STARTSERVODRESPONSE_SUCCESS,
+    '__module__' : 'chromiumos.test.api.servod_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.StartServodResponse.Success)
+    })
+  ,
+
+  'Failure' : _reflection.GeneratedProtocolMessageType('Failure', (_message.Message,), {
+    'DESCRIPTOR' : _STARTSERVODRESPONSE_FAILURE,
+    '__module__' : 'chromiumos.test.api.servod_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.StartServodResponse.Failure)
+    })
+  ,
+  'DESCRIPTOR' : _STARTSERVODRESPONSE,
+  '__module__' : 'chromiumos.test.api.servod_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.StartServodResponse)
+  })
+_sym_db.RegisterMessage(StartServodResponse)
+_sym_db.RegisterMessage(StartServodResponse.Success)
+_sym_db.RegisterMessage(StartServodResponse.Failure)
+
+StartServodMetadata = _reflection.GeneratedProtocolMessageType('StartServodMetadata', (_message.Message,), {
+  'DESCRIPTOR' : _STARTSERVODMETADATA,
+  '__module__' : 'chromiumos.test.api.servod_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.StartServodMetadata)
+  })
+_sym_db.RegisterMessage(StartServodMetadata)
+
+StopServodRequest = _reflection.GeneratedProtocolMessageType('StopServodRequest', (_message.Message,), {
+  'DESCRIPTOR' : _STOPSERVODREQUEST,
+  '__module__' : 'chromiumos.test.api.servod_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.StopServodRequest)
+  })
+_sym_db.RegisterMessage(StopServodRequest)
+
+StopServodResponse = _reflection.GeneratedProtocolMessageType('StopServodResponse', (_message.Message,), {
+
+  'Success' : _reflection.GeneratedProtocolMessageType('Success', (_message.Message,), {
+    'DESCRIPTOR' : _STOPSERVODRESPONSE_SUCCESS,
+    '__module__' : 'chromiumos.test.api.servod_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.StopServodResponse.Success)
+    })
+  ,
+
+  'Failure' : _reflection.GeneratedProtocolMessageType('Failure', (_message.Message,), {
+    'DESCRIPTOR' : _STOPSERVODRESPONSE_FAILURE,
+    '__module__' : 'chromiumos.test.api.servod_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.StopServodResponse.Failure)
+    })
+  ,
+  'DESCRIPTOR' : _STOPSERVODRESPONSE,
+  '__module__' : 'chromiumos.test.api.servod_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.StopServodResponse)
+  })
+_sym_db.RegisterMessage(StopServodResponse)
+_sym_db.RegisterMessage(StopServodResponse.Success)
+_sym_db.RegisterMessage(StopServodResponse.Failure)
+
+StopServodMetadata = _reflection.GeneratedProtocolMessageType('StopServodMetadata', (_message.Message,), {
+  'DESCRIPTOR' : _STOPSERVODMETADATA,
+  '__module__' : 'chromiumos.test.api.servod_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.StopServodMetadata)
+  })
+_sym_db.RegisterMessage(StopServodMetadata)
+
+ExecCmdRequest = _reflection.GeneratedProtocolMessageType('ExecCmdRequest', (_message.Message,), {
+  'DESCRIPTOR' : _EXECCMDREQUEST,
+  '__module__' : 'chromiumos.test.api.servod_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.ExecCmdRequest)
+  })
+_sym_db.RegisterMessage(ExecCmdRequest)
+
+ExecCmdResponse = _reflection.GeneratedProtocolMessageType('ExecCmdResponse', (_message.Message,), {
+
+  'ExitInfo' : _reflection.GeneratedProtocolMessageType('ExitInfo', (_message.Message,), {
+    'DESCRIPTOR' : _EXECCMDRESPONSE_EXITINFO,
+    '__module__' : 'chromiumos.test.api.servod_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.ExecCmdResponse.ExitInfo)
+    })
+  ,
+  'DESCRIPTOR' : _EXECCMDRESPONSE,
+  '__module__' : 'chromiumos.test.api.servod_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.ExecCmdResponse)
+  })
+_sym_db.RegisterMessage(ExecCmdResponse)
+_sym_db.RegisterMessage(ExecCmdResponse.ExitInfo)
+
+ExecCmdMetadata = _reflection.GeneratedProtocolMessageType('ExecCmdMetadata', (_message.Message,), {
+  'DESCRIPTOR' : _EXECCMDMETADATA,
+  '__module__' : 'chromiumos.test.api.servod_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.ExecCmdMetadata)
+  })
+_sym_db.RegisterMessage(ExecCmdMetadata)
+
+CallServodRequest = _reflection.GeneratedProtocolMessageType('CallServodRequest', (_message.Message,), {
+  'DESCRIPTOR' : _CALLSERVODREQUEST,
+  '__module__' : 'chromiumos.test.api.servod_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.CallServodRequest)
+  })
+_sym_db.RegisterMessage(CallServodRequest)
+
+CallServodResponse = _reflection.GeneratedProtocolMessageType('CallServodResponse', (_message.Message,), {
+
+  'Success' : _reflection.GeneratedProtocolMessageType('Success', (_message.Message,), {
+    'DESCRIPTOR' : _CALLSERVODRESPONSE_SUCCESS,
+    '__module__' : 'chromiumos.test.api.servod_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.CallServodResponse.Success)
+    })
+  ,
+
+  'Failure' : _reflection.GeneratedProtocolMessageType('Failure', (_message.Message,), {
+    'DESCRIPTOR' : _CALLSERVODRESPONSE_FAILURE,
+    '__module__' : 'chromiumos.test.api.servod_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.CallServodResponse.Failure)
+    })
+  ,
+  'DESCRIPTOR' : _CALLSERVODRESPONSE,
+  '__module__' : 'chromiumos.test.api.servod_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.CallServodResponse)
+  })
+_sym_db.RegisterMessage(CallServodResponse)
+_sym_db.RegisterMessage(CallServodResponse.Success)
+_sym_db.RegisterMessage(CallServodResponse.Failure)
+
+CallServodMetadata = _reflection.GeneratedProtocolMessageType('CallServodMetadata', (_message.Message,), {
+  'DESCRIPTOR' : _CALLSERVODMETADATA,
+  '__module__' : 'chromiumos.test.api.servod_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.CallServodMetadata)
+  })
+_sym_db.RegisterMessage(CallServodMetadata)
+
+
+DESCRIPTOR._options = None
+
+_SERVODSERVICE = _descriptor.ServiceDescriptor(
+  name='ServodService',
+  full_name='chromiumos.test.api.ServodService',
+  file=DESCRIPTOR,
+  index=0,
+  serialized_options=None,
+  create_key=_descriptor._internal_create_key,
+  serialized_start=1909,
+  serialized_end=2379,
+  methods=[
+  _descriptor.MethodDescriptor(
+    name='StartServod',
+    full_name='chromiumos.test.api.ServodService.StartServod',
+    index=0,
+    containing_service=None,
+    input_type=_STARTSERVODREQUEST,
+    output_type=chromiumos_dot_longrunning_dot_operations__pb2._OPERATION,
+    serialized_options=b'\322A*\n\023StartServodResponse\022\023StartServodMetadata',
+    create_key=_descriptor._internal_create_key,
+  ),
+  _descriptor.MethodDescriptor(
+    name='StopServod',
+    full_name='chromiumos.test.api.ServodService.StopServod',
+    index=1,
+    containing_service=None,
+    input_type=_STOPSERVODREQUEST,
+    output_type=chromiumos_dot_longrunning_dot_operations__pb2._OPERATION,
+    serialized_options=b'\322A(\n\022StopServodResponse\022\022StopServodMetadata',
+    create_key=_descriptor._internal_create_key,
+  ),
+  _descriptor.MethodDescriptor(
+    name='ExecCmd',
+    full_name='chromiumos.test.api.ServodService.ExecCmd',
+    index=2,
+    containing_service=None,
+    input_type=_EXECCMDREQUEST,
+    output_type=_EXECCMDRESPONSE,
+    serialized_options=None,
+    create_key=_descriptor._internal_create_key,
+  ),
+  _descriptor.MethodDescriptor(
+    name='CallServod',
+    full_name='chromiumos.test.api.ServodService.CallServod',
+    index=3,
+    containing_service=None,
+    input_type=_CALLSERVODREQUEST,
+    output_type=_CALLSERVODRESPONSE,
+    serialized_options=None,
+    create_key=_descriptor._internal_create_key,
+  ),
+])
+_sym_db.RegisterServiceDescriptor(_SERVODSERVICE)
+
+DESCRIPTOR.services_by_name['ServodService'] = _SERVODSERVICE
+
+# @@protoc_insertion_point(module_scope)
diff --git a/api/gen/chromiumos/test/api/test_harness_pb2.py b/api/gen/chromiumos/test/api/test_harness_pb2.py
index acc64a9..13958f7 100644
--- a/api/gen/chromiumos/test/api/test_harness_pb2.py
+++ b/api/gen/chromiumos/test/api/test_harness_pb2.py
@@ -19,7 +19,7 @@
   syntax='proto3',
   serialized_options=b'Z-go.chromium.org/chromiumos/config/go/test/api',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n&chromiumos/test/api/test_harness.proto\x12\x13\x63hromiumos.test.api\"\xaa\x02\n\x0bTestHarness\x12\x39\n\x06manual\x18\x01 \x01(\x0b\x32\'.chromiumos.test.api.TestHarness.ManualH\x00\x12\x37\n\x05tauto\x18\x02 \x01(\x0b\x32&.chromiumos.test.api.TestHarness.TautoH\x00\x12\x35\n\x04tast\x18\x03 \x01(\x0b\x32%.chromiumos.test.api.TestHarness.TastH\x00\x12\x37\n\x05gtest\x18\x04 \x01(\x0b\x32&.chromiumos.test.api.TestHarness.GtestH\x00\x1a\x08\n\x06Manual\x1a\x06\n\x04Tast\x1a\x07\n\x05Tauto\x1a\x07\n\x05GtestB\x13\n\x11test_harness_typeB/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
+  serialized_pb=b'\n&chromiumos/test/api/test_harness.proto\x12\x13\x63hromiumos.test.api\"\xc7\x02\n\x0bTestHarness\x12\x39\n\x06manual\x18\x01 \x01(\x0b\x32\'.chromiumos.test.api.TestHarness.ManualH\x00\x12\x37\n\x05tauto\x18\x02 \x01(\x0b\x32&.chromiumos.test.api.TestHarness.TautoH\x00\x12\x35\n\x04tast\x18\x03 \x01(\x0b\x32%.chromiumos.test.api.TestHarness.TastH\x00\x12\x37\n\x05gtest\x18\x04 \x01(\x0b\x32&.chromiumos.test.api.TestHarness.GtestH\x00\x1a\x08\n\x06Manual\x1a\x06\n\x04Tast\x1a\x07\n\x05Tauto\x1a$\n\x05Gtest\x12\x1b\n\x13target_bin_location\x18\x01 \x01(\tB\x13\n\x11test_harness_typeB/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
 )
 
 
@@ -105,6 +105,13 @@
   containing_type=None,
   create_key=_descriptor._internal_create_key,
   fields=[
+    _descriptor.FieldDescriptor(
+      name='target_bin_location', full_name='chromiumos.test.api.TestHarness.Gtest.target_bin_location', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -118,7 +125,7 @@
   oneofs=[
   ],
   serialized_start=334,
-  serialized_end=341,
+  serialized_end=370,
 )
 
 _TESTHARNESS = _descriptor.Descriptor(
@@ -175,7 +182,7 @@
     fields=[]),
   ],
   serialized_start=64,
-  serialized_end=362,
+  serialized_end=391,
 )
 
 _TESTHARNESS_MANUAL.containing_type = _TESTHARNESS
diff --git a/api/gen/chromiumos/test/api/v1/__init__.py b/api/gen/chromiumos/test/api/v1/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/api/gen/chromiumos/test/api/v1/__init__.py
diff --git a/api/gen/chromiumos/test/api/v1/plan_pb2.py b/api/gen/chromiumos/test/api/v1/plan_pb2.py
new file mode 100644
index 0000000..95970cd
--- /dev/null
+++ b/api/gen/chromiumos/test/api/v1/plan_pb2.py
@@ -0,0 +1,122 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: chromiumos/test/api/v1/plan.proto
+"""Generated protocol buffer code."""
+from chromite.third_party.google.protobuf import descriptor as _descriptor
+from chromite.third_party.google.protobuf import message as _message
+from chromite.third_party.google.protobuf import reflection as _reflection
+from chromite.third_party.google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from chromite.api.gen.chromiumos.test.api import coverage_rule_pb2 as chromiumos_dot_test_dot_api_dot_coverage__rule__pb2
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='chromiumos/test/api/v1/plan.proto',
+  package='chromiumos.test.api.v1',
+  syntax='proto3',
+  serialized_options=b'Z<go.chromium.org/chromiumos/config/go/test/api/v1;test_api_v1',
+  create_key=_descriptor._internal_create_key,
+  serialized_pb=b'\n!chromiumos/test/api/v1/plan.proto\x12\x16\x63hromiumos.test.api.v1\x1a\'chromiumos/test/api/coverage_rule.proto\"\x9f\x01\n\nHWTestPlan\x12\x39\n\x02id\x18\x01 \x01(\x0b\x32-.chromiumos.test.api.v1.HWTestPlan.TestPlanId\x12\x39\n\x0e\x63overage_rules\x18\x02 \x03(\x0b\x32!.chromiumos.test.api.CoverageRule\x1a\x1b\n\nTestPlanId\x12\r\n\x05value\x18\x01 \x01(\tB>Z<go.chromium.org/chromiumos/config/go/test/api/v1;test_api_v1b\x06proto3'
+  ,
+  dependencies=[chromiumos_dot_test_dot_api_dot_coverage__rule__pb2.DESCRIPTOR,])
+
+
+
+
+_HWTESTPLAN_TESTPLANID = _descriptor.Descriptor(
+  name='TestPlanId',
+  full_name='chromiumos.test.api.v1.HWTestPlan.TestPlanId',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='value', full_name='chromiumos.test.api.v1.HWTestPlan.TestPlanId.value', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=235,
+  serialized_end=262,
+)
+
+_HWTESTPLAN = _descriptor.Descriptor(
+  name='HWTestPlan',
+  full_name='chromiumos.test.api.v1.HWTestPlan',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='id', full_name='chromiumos.test.api.v1.HWTestPlan.id', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='coverage_rules', full_name='chromiumos.test.api.v1.HWTestPlan.coverage_rules', index=1,
+      number=2, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[_HWTESTPLAN_TESTPLANID, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=103,
+  serialized_end=262,
+)
+
+_HWTESTPLAN_TESTPLANID.containing_type = _HWTESTPLAN
+_HWTESTPLAN.fields_by_name['id'].message_type = _HWTESTPLAN_TESTPLANID
+_HWTESTPLAN.fields_by_name['coverage_rules'].message_type = chromiumos_dot_test_dot_api_dot_coverage__rule__pb2._COVERAGERULE
+DESCRIPTOR.message_types_by_name['HWTestPlan'] = _HWTESTPLAN
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+HWTestPlan = _reflection.GeneratedProtocolMessageType('HWTestPlan', (_message.Message,), {
+
+  'TestPlanId' : _reflection.GeneratedProtocolMessageType('TestPlanId', (_message.Message,), {
+    'DESCRIPTOR' : _HWTESTPLAN_TESTPLANID,
+    '__module__' : 'chromiumos.test.api.v1.plan_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.v1.HWTestPlan.TestPlanId)
+    })
+  ,
+  'DESCRIPTOR' : _HWTESTPLAN,
+  '__module__' : 'chromiumos.test.api.v1.plan_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.v1.HWTestPlan)
+  })
+_sym_db.RegisterMessage(HWTestPlan)
+_sym_db.RegisterMessage(HWTestPlan.TestPlanId)
+
+
+DESCRIPTOR._options = None
+# @@protoc_insertion_point(module_scope)
diff --git a/api/gen/chromiumos/test/artifact/dut_metadata_artifact_pb2.py b/api/gen/chromiumos/test/artifact/dut_metadata_artifact_pb2.py
new file mode 100644
index 0000000..59f8107
--- /dev/null
+++ b/api/gen/chromiumos/test/artifact/dut_metadata_artifact_pb2.py
@@ -0,0 +1,124 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: chromiumos/test/artifact/dut_metadata_artifact.proto
+"""Generated protocol buffer code."""
+from chromite.third_party.google.protobuf import descriptor as _descriptor
+from chromite.third_party.google.protobuf import message as _message
+from chromite.third_party.google.protobuf import reflection as _reflection
+from chromite.third_party.google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from chromite.api.gen.chromiumos.test.api import provision_state_pb2 as chromiumos_dot_test_dot_api_dot_provision__state__pb2
+from chromite.api.gen.chromiumos.test.lab.api import dut_pb2 as chromiumos_dot_test_dot_lab_dot_api_dot_dut__pb2
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='chromiumos/test/artifact/dut_metadata_artifact.proto',
+  package='chromiumos.test.artifact',
+  syntax='proto3',
+  serialized_options=b'Z2go.chromium.org/chromiumos/config/go/test/artifact',
+  create_key=_descriptor._internal_create_key,
+  serialized_pb=b'\n4chromiumos/test/artifact/dut_metadata_artifact.proto\x12\x18\x63hromiumos.test.artifact\x1a)chromiumos/test/api/provision_state.proto\x1a!chromiumos/test/lab/api/dut.proto\"\\\n\x13\x44utMetadataArtifact\x12\x45\n\x12\x64ut_info_artifacts\x18\x01 \x03(\x0b\x32).chromiumos.test.artifact.DutInfoArtifact\"z\n\x0f\x44utInfoArtifact\x12)\n\x03\x64ut\x18\x01 \x01(\x0b\x32\x1c.chromiumos.test.lab.api.Dut\x12<\n\x0fprovision_state\x18\x02 \x01(\x0b\x32#.chromiumos.test.api.ProvisionStateB4Z2go.chromium.org/chromiumos/config/go/test/artifactb\x06proto3'
+  ,
+  dependencies=[chromiumos_dot_test_dot_api_dot_provision__state__pb2.DESCRIPTOR,chromiumos_dot_test_dot_lab_dot_api_dot_dut__pb2.DESCRIPTOR,])
+
+
+
+
+_DUTMETADATAARTIFACT = _descriptor.Descriptor(
+  name='DutMetadataArtifact',
+  full_name='chromiumos.test.artifact.DutMetadataArtifact',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='dut_info_artifacts', full_name='chromiumos.test.artifact.DutMetadataArtifact.dut_info_artifacts', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=160,
+  serialized_end=252,
+)
+
+
+_DUTINFOARTIFACT = _descriptor.Descriptor(
+  name='DutInfoArtifact',
+  full_name='chromiumos.test.artifact.DutInfoArtifact',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='dut', full_name='chromiumos.test.artifact.DutInfoArtifact.dut', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='provision_state', full_name='chromiumos.test.artifact.DutInfoArtifact.provision_state', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=254,
+  serialized_end=376,
+)
+
+_DUTMETADATAARTIFACT.fields_by_name['dut_info_artifacts'].message_type = _DUTINFOARTIFACT
+_DUTINFOARTIFACT.fields_by_name['dut'].message_type = chromiumos_dot_test_dot_lab_dot_api_dot_dut__pb2._DUT
+_DUTINFOARTIFACT.fields_by_name['provision_state'].message_type = chromiumos_dot_test_dot_api_dot_provision__state__pb2._PROVISIONSTATE
+DESCRIPTOR.message_types_by_name['DutMetadataArtifact'] = _DUTMETADATAARTIFACT
+DESCRIPTOR.message_types_by_name['DutInfoArtifact'] = _DUTINFOARTIFACT
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+DutMetadataArtifact = _reflection.GeneratedProtocolMessageType('DutMetadataArtifact', (_message.Message,), {
+  'DESCRIPTOR' : _DUTMETADATAARTIFACT,
+  '__module__' : 'chromiumos.test.artifact.dut_metadata_artifact_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.artifact.DutMetadataArtifact)
+  })
+_sym_db.RegisterMessage(DutMetadataArtifact)
+
+DutInfoArtifact = _reflection.GeneratedProtocolMessageType('DutInfoArtifact', (_message.Message,), {
+  'DESCRIPTOR' : _DUTINFOARTIFACT,
+  '__module__' : 'chromiumos.test.artifact.dut_metadata_artifact_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.artifact.DutInfoArtifact)
+  })
+_sym_db.RegisterMessage(DutInfoArtifact)
+
+
+DESCRIPTOR._options = None
+# @@protoc_insertion_point(module_scope)
diff --git a/api/gen/chromiumos/test/artifact/manifest_pb2.py b/api/gen/chromiumos/test/artifact/manifest_pb2.py
index 92b4ae4..fdbcc57 100644
--- a/api/gen/chromiumos/test/artifact/manifest_pb2.py
+++ b/api/gen/chromiumos/test/artifact/manifest_pb2.py
@@ -11,6 +11,7 @@
 _sym_db = _symbol_database.Default()
 
 
+from chromite.api.gen.chromiumos import storage_path_pb2 as chromiumos_dot_storage__path__pb2
 
 
 DESCRIPTOR = _descriptor.FileDescriptor(
@@ -19,8 +20,9 @@
   syntax='proto3',
   serialized_options=b'Z2go.chromium.org/chromiumos/config/go/test/artifact',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n\'chromiumos/test/artifact/manifest.proto\x12\x18\x63hromiumos.test.artifact\"R\n\x08Manifest\x12\x0f\n\x07version\x18\x01 \x01(\r\x12\x35\n\tartifacts\x18\x02 \x03(\x0b\x32\".chromiumos.test.artifact.Artifact\"\x99\x01\n\x08\x41rtifact\x12=\n\x04type\x18\x01 \x01(\x0e\x32/.chromiumos.test.artifact.Artifact.ArtifactType\x12\x0e\n\x06gs_url\x18\x02 \x01(\t\">\n\x0c\x41rtifactType\x12\x1d\n\x19\x41RTIFACT_TYPE_UNSPECIFIED\x10\x00\x12\x0f\n\x0bTEST_RESULT\x10\x01\x42\x34Z2go.chromium.org/chromiumos/config/go/test/artifactb\x06proto3'
-)
+  serialized_pb=b'\n\'chromiumos/test/artifact/manifest.proto\x12\x18\x63hromiumos.test.artifact\x1a\x1d\x63hromiumos/storage_path.proto\"R\n\x08Manifest\x12\x0f\n\x07version\x18\x01 \x01(\r\x12\x35\n\tartifacts\x18\x02 \x03(\x0b\x32\".chromiumos.test.artifact.Artifact\"\xd9\x01\n\x08\x41rtifact\x12=\n\x04type\x18\x01 \x01(\x0e\x32/.chromiumos.test.artifact.Artifact.ArtifactType\x12-\n\x0cstorage_path\x18\x02 \x01(\x0b\x32\x17.chromiumos.StoragePath\"_\n\x0c\x41rtifactType\x12\x1d\n\x19\x41RTIFACT_TYPE_UNSPECIFIED\x10\x00\x12\x0f\n\x0bTEST_RESULT\x10\x01\x12\x10\n\x0c\x44UT_METADATA\x10\x02\x12\r\n\tTEST_PLAN\x10\x03\x42\x34Z2go.chromium.org/chromiumos/config/go/test/artifactb\x06proto3'
+  ,
+  dependencies=[chromiumos_dot_storage__path__pb2.DESCRIPTOR,])
 
 
 
@@ -41,11 +43,21 @@
       serialized_options=None,
       type=None,
       create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='DUT_METADATA', index=2, number=2,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TEST_PLAN', index=3, number=3,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=245,
-  serialized_end=307,
+  serialized_start=307,
+  serialized_end=402,
 )
 _sym_db.RegisterEnumDescriptor(_ARTIFACT_ARTIFACTTYPE)
 
@@ -84,8 +96,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=69,
-  serialized_end=151,
+  serialized_start=100,
+  serialized_end=182,
 )
 
 
@@ -105,9 +117,9 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='gs_url', full_name='chromiumos.test.artifact.Artifact.gs_url', index=1,
-      number=2, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=b"".decode('utf-8'),
+      name='storage_path', full_name='chromiumos.test.artifact.Artifact.storage_path', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
@@ -124,12 +136,13 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=154,
-  serialized_end=307,
+  serialized_start=185,
+  serialized_end=402,
 )
 
 _MANIFEST.fields_by_name['artifacts'].message_type = _ARTIFACT
 _ARTIFACT.fields_by_name['type'].enum_type = _ARTIFACT_ARTIFACTTYPE
+_ARTIFACT.fields_by_name['storage_path'].message_type = chromiumos_dot_storage__path__pb2._STORAGEPATH
 _ARTIFACT_ARTIFACTTYPE.containing_type = _ARTIFACT
 DESCRIPTOR.message_types_by_name['Manifest'] = _MANIFEST
 DESCRIPTOR.message_types_by_name['Artifact'] = _ARTIFACT
diff --git a/api/gen/chromiumos/test/artifact/test_plan_pb2.py b/api/gen/chromiumos/test/artifact/test_plan_pb2.py
new file mode 100644
index 0000000..2ad7fb7
--- /dev/null
+++ b/api/gen/chromiumos/test/artifact/test_plan_pb2.py
@@ -0,0 +1,74 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: chromiumos/test/artifact/test_plan.proto
+"""Generated protocol buffer code."""
+from chromite.third_party.google.protobuf import descriptor as _descriptor
+from chromite.third_party.google.protobuf import message as _message
+from chromite.third_party.google.protobuf import reflection as _reflection
+from chromite.third_party.google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from chromite.api.gen.chromiumos.test.api.v1 import plan_pb2 as chromiumos_dot_test_dot_api_dot_v1_dot_plan__pb2
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='chromiumos/test/artifact/test_plan.proto',
+  package='chromiumos.test.artifact',
+  syntax='proto3',
+  serialized_options=b'Z2go.chromium.org/chromiumos/config/go/test/artifact',
+  create_key=_descriptor._internal_create_key,
+  serialized_pb=b'\n(chromiumos/test/artifact/test_plan.proto\x12\x18\x63hromiumos.test.artifact\x1a!chromiumos/test/api/v1/plan.proto\"M\n\x10TestPlanArtifact\x12\x39\n\rhw_test_plans\x18\x01 \x03(\x0b\x32\".chromiumos.test.api.v1.HWTestPlanB4Z2go.chromium.org/chromiumos/config/go/test/artifactb\x06proto3'
+  ,
+  dependencies=[chromiumos_dot_test_dot_api_dot_v1_dot_plan__pb2.DESCRIPTOR,])
+
+
+
+
+_TESTPLANARTIFACT = _descriptor.Descriptor(
+  name='TestPlanArtifact',
+  full_name='chromiumos.test.artifact.TestPlanArtifact',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='hw_test_plans', full_name='chromiumos.test.artifact.TestPlanArtifact.hw_test_plans', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=105,
+  serialized_end=182,
+)
+
+_TESTPLANARTIFACT.fields_by_name['hw_test_plans'].message_type = chromiumos_dot_test_dot_api_dot_v1_dot_plan__pb2._HWTESTPLAN
+DESCRIPTOR.message_types_by_name['TestPlanArtifact'] = _TESTPLANARTIFACT
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+TestPlanArtifact = _reflection.GeneratedProtocolMessageType('TestPlanArtifact', (_message.Message,), {
+  'DESCRIPTOR' : _TESTPLANARTIFACT,
+  '__module__' : 'chromiumos.test.artifact.test_plan_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.artifact.TestPlanArtifact)
+  })
+_sym_db.RegisterMessage(TestPlanArtifact)
+
+
+DESCRIPTOR._options = None
+# @@protoc_insertion_point(module_scope)
diff --git a/api/gen/chromiumos/test/artifact/test_result_pb2.py b/api/gen/chromiumos/test/artifact/test_result_pb2.py
index e2f59c4..ad115ea 100644
--- a/api/gen/chromiumos/test/artifact/test_result_pb2.py
+++ b/api/gen/chromiumos/test/artifact/test_result_pb2.py
@@ -12,9 +12,11 @@
 
 
 from chromite.api.gen.chromiumos import storage_path_pb2 as chromiumos_dot_storage__path__pb2
+from chromite.api.gen.chromiumos.test.api import provision_state_pb2 as chromiumos_dot_test_dot_api_dot_provision__state__pb2
 from chromite.api.gen.chromiumos.test.api import test_case_pb2 as chromiumos_dot_test_dot_api_dot_test__case__pb2
 from chromite.api.gen.chromiumos.test.api import test_case_metadata_pb2 as chromiumos_dot_test_dot_api_dot_test__case__metadata__pb2
 from chromite.api.gen.chromiumos.test.api import test_case_result_pb2 as chromiumos_dot_test_dot_api_dot_test__case__result__pb2
+from chromite.api.gen.chromiumos.test.api.v1 import plan_pb2 as chromiumos_dot_test_dot_api_dot_v1_dot_plan__pb2
 from chromite.api.gen.chromiumos.test.lab.api import dut_pb2 as chromiumos_dot_test_dot_lab_dot_api_dot_dut__pb2
 
 
@@ -24,9 +26,9 @@
   syntax='proto3',
   serialized_options=b'Z2go.chromium.org/chromiumos/config/go/test/artifact',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n*chromiumos/test/artifact/test_result.proto\x12\x18\x63hromiumos.test.artifact\x1a\x1d\x63hromiumos/storage_path.proto\x1a#chromiumos/test/api/test_case.proto\x1a,chromiumos/test/api/test_case_metadata.proto\x1a*chromiumos/test/api/test_case_result.proto\x1a!chromiumos/test/lab/api/dut.proto\"\x93\x01\n\nTestResult\x12\x0f\n\x07version\x18\x01 \x01(\r\x12\x34\n\ttest_runs\x18\x02 \x03(\x0b\x32!.chromiumos.test.artifact.TestRun\x12>\n\x0e\x63ustom_results\x18\x03 \x03(\x0b\x32&.chromiumos.test.artifact.CustomResult\"\xff\x02\n\x07TestRun\x12\x30\n\ttest_case\x18\x01 \x01(\x0b\x32\x1d.chromiumos.test.api.TestCase\x12\x41\n\x12test_case_metadata\x18\x02 \x01(\x0b\x32%.chromiumos.test.api.TestCaseMetadata\x12=\n\x10test_case_result\x18\x03 \x01(\x0b\x32#.chromiumos.test.api.TestCaseResult\x12\x11\n\tbuild_ids\x18\x04 \x03(\x04\x12:\n\x0c\x64ut_topology\x18\x05 \x01(\x0b\x32$.chromiumos.test.lab.api.DutTopology\x12\x36\n\x0bprimary_dut\x18\x06 \x01(\x0b\x32!.chromiumos.test.artifact.DutInfo\x12\x39\n\x0e\x63ompanion_duts\x18\x07 \x03(\x0b\x32!.chromiumos.test.artifact.DutInfo\"\x9e\x01\n\x07\x44utInfo\x12+\n\x02id\x18\x01 \x01(\x0b\x32\x1f.chromiumos.test.lab.api.Dut.Id\x12\x39\n\x04tags\x18\x02 \x03(\x0b\x32+.chromiumos.test.artifact.DutInfo.TagsEntry\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x8a\x01\n\x0c\x43ustomResult\x12\x30\n\x0fresult_dir_path\x18\x01 \x01(\x0b\x32\x17.chromiumos.StoragePath\x12\x39\n\x03\x63ts\x18\x02 \x01(\x0b\x32*.chromiumos.test.artifact.CustomResult.CtsH\x00\x1a\x05\n\x03\x43tsB\x06\n\x04typeB4Z2go.chromium.org/chromiumos/config/go/test/artifactb\x06proto3'
+  serialized_pb=b'\n*chromiumos/test/artifact/test_result.proto\x12\x18\x63hromiumos.test.artifact\x1a\x1d\x63hromiumos/storage_path.proto\x1a)chromiumos/test/api/provision_state.proto\x1a#chromiumos/test/api/test_case.proto\x1a,chromiumos/test/api/test_case_metadata.proto\x1a*chromiumos/test/api/test_case_result.proto\x1a!chromiumos/test/api/v1/plan.proto\x1a!chromiumos/test/lab/api/dut.proto\"\xd9\x01\n\nTestResult\x12\x0f\n\x07version\x18\x01 \x01(\r\x12\x34\n\ttest_runs\x18\x02 \x03(\x0b\x32!.chromiumos.test.artifact.TestRun\x12>\n\x0e\x63ustom_results\x18\x03 \x03(\x0b\x32&.chromiumos.test.artifact.CustomResult\x12\x44\n\rtest_plan_ids\x18\x04 \x03(\x0b\x32-.chromiumos.test.api.v1.HWTestPlan.TestPlanId\"\xff\x02\n\x07TestRun\x12\x30\n\ttest_case\x18\x01 \x01(\x0b\x32\x1d.chromiumos.test.api.TestCase\x12\x41\n\x12test_case_metadata\x18\x02 \x01(\x0b\x32%.chromiumos.test.api.TestCaseMetadata\x12=\n\x10test_case_result\x18\x03 \x01(\x0b\x32#.chromiumos.test.api.TestCaseResult\x12\x11\n\tbuild_ids\x18\x04 \x03(\x04\x12:\n\x0c\x64ut_topology\x18\x05 \x01(\x0b\x32$.chromiumos.test.lab.api.DutTopology\x12\x36\n\x0bprimary_dut\x18\x06 \x01(\x0b\x32!.chromiumos.test.artifact.DutInfo\x12\x39\n\x0e\x63ompanion_duts\x18\x07 \x03(\x0b\x32!.chromiumos.test.artifact.DutInfo\"\xe2\x01\n\x07\x44utInfo\x12+\n\x02id\x18\x01 \x01(\x0b\x32\x1f.chromiumos.test.lab.api.Dut.Id\x12\x42\n\x12provision_state_id\x18\x03 \x01(\x0b\x32&.chromiumos.test.api.ProvisionState.Id\x12\x39\n\x04tags\x18\x02 \x03(\x0b\x32+.chromiumos.test.artifact.DutInfo.TagsEntry\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x8a\x01\n\x0c\x43ustomResult\x12\x30\n\x0fresult_dir_path\x18\x01 \x01(\x0b\x32\x17.chromiumos.StoragePath\x12\x39\n\x03\x63ts\x18\x02 \x01(\x0b\x32*.chromiumos.test.artifact.CustomResult.CtsH\x00\x1a\x05\n\x03\x43tsB\x06\n\x04typeB4Z2go.chromium.org/chromiumos/config/go/test/artifactb\x06proto3'
   ,
-  dependencies=[chromiumos_dot_storage__path__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_test__case__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_test__case__metadata__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_test__case__result__pb2.DESCRIPTOR,chromiumos_dot_test_dot_lab_dot_api_dot_dut__pb2.DESCRIPTOR,])
+  dependencies=[chromiumos_dot_storage__path__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_provision__state__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_test__case__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_test__case__metadata__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_test__case__result__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_v1_dot_plan__pb2.DESCRIPTOR,chromiumos_dot_test_dot_lab_dot_api_dot_dut__pb2.DESCRIPTOR,])
 
 
 
@@ -60,6 +62,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='test_plan_ids', full_name='chromiumos.test.artifact.TestResult.test_plan_ids', index=3,
+      number=4, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -72,8 +81,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=266,
-  serialized_end=413,
+  serialized_start=344,
+  serialized_end=561,
 )
 
 
@@ -146,8 +155,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=416,
-  serialized_end=799,
+  serialized_start=564,
+  serialized_end=947,
 )
 
 
@@ -185,8 +194,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=917,
-  serialized_end=960,
+  serialized_start=1133,
+  serialized_end=1176,
 )
 
 _DUTINFO = _descriptor.Descriptor(
@@ -205,7 +214,14 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='tags', full_name='chromiumos.test.artifact.DutInfo.tags', index=1,
+      name='provision_state_id', full_name='chromiumos.test.artifact.DutInfo.provision_state_id', index=1,
+      number=3, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='tags', full_name='chromiumos.test.artifact.DutInfo.tags', index=2,
       number=2, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
@@ -223,8 +239,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=802,
-  serialized_end=960,
+  serialized_start=950,
+  serialized_end=1176,
 )
 
 
@@ -248,8 +264,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1088,
-  serialized_end=1093,
+  serialized_start=1304,
+  serialized_end=1309,
 )
 
 _CUSTOMRESULT = _descriptor.Descriptor(
@@ -291,12 +307,13 @@
       create_key=_descriptor._internal_create_key,
     fields=[]),
   ],
-  serialized_start=963,
-  serialized_end=1101,
+  serialized_start=1179,
+  serialized_end=1317,
 )
 
 _TESTRESULT.fields_by_name['test_runs'].message_type = _TESTRUN
 _TESTRESULT.fields_by_name['custom_results'].message_type = _CUSTOMRESULT
+_TESTRESULT.fields_by_name['test_plan_ids'].message_type = chromiumos_dot_test_dot_api_dot_v1_dot_plan__pb2._HWTESTPLAN_TESTPLANID
 _TESTRUN.fields_by_name['test_case'].message_type = chromiumos_dot_test_dot_api_dot_test__case__pb2._TESTCASE
 _TESTRUN.fields_by_name['test_case_metadata'].message_type = chromiumos_dot_test_dot_api_dot_test__case__metadata__pb2._TESTCASEMETADATA
 _TESTRUN.fields_by_name['test_case_result'].message_type = chromiumos_dot_test_dot_api_dot_test__case__result__pb2._TESTCASERESULT
@@ -305,6 +322,7 @@
 _TESTRUN.fields_by_name['companion_duts'].message_type = _DUTINFO
 _DUTINFO_TAGSENTRY.containing_type = _DUTINFO
 _DUTINFO.fields_by_name['id'].message_type = chromiumos_dot_test_dot_lab_dot_api_dot_dut__pb2._DUT_ID
+_DUTINFO.fields_by_name['provision_state_id'].message_type = chromiumos_dot_test_dot_api_dot_provision__state__pb2._PROVISIONSTATE_ID
 _DUTINFO.fields_by_name['tags'].message_type = _DUTINFO_TAGSENTRY
 _CUSTOMRESULT_CTS.containing_type = _CUSTOMRESULT
 _CUSTOMRESULT.fields_by_name['result_dir_path'].message_type = chromiumos_dot_storage__path__pb2._STORAGEPATH
diff --git a/api/gen/chromiumos/test/lab/api/dut_pb2.py b/api/gen/chromiumos/test/lab/api/dut_pb2.py
index 966ec91..b93a586 100644
--- a/api/gen/chromiumos/test/lab/api/dut_pb2.py
+++ b/api/gen/chromiumos/test/lab/api/dut_pb2.py
@@ -21,7 +21,7 @@
   syntax='proto3',
   serialized_options=b'Z1go.chromium.org/chromiumos/config/go/test/lab/api',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n!chromiumos/test/lab/api/dut.proto\x12\x17\x63hromiumos.test.lab.api\x1a,chromiumos/config/api/device_config_id.proto\x1a)chromiumos/test/lab/api/ip_endpoint.proto\"\x8f\x07\n\x03\x44ut\x12+\n\x02id\x18\x01 \x01(\x0b\x32\x1f.chromiumos.test.lab.api.Dut.Id\x12\x39\n\x08\x63hromeos\x18\x02 \x01(\x0b\x32%.chromiumos.test.lab.api.Dut.ChromeOSH\x00\x12\x37\n\x07\x61ndroid\x18\x03 \x01(\x0b\x32$.chromiumos.test.lab.api.Dut.AndroidH\x00\x12:\n\x0c\x63\x61\x63he_server\x18\x0e \x01(\x0b\x32$.chromiumos.test.lab.api.CacheServer\x1a\x13\n\x02Id\x12\r\n\x05value\x18\x01 \x01(\t\x1a\xfe\x04\n\x08\x43hromeOS\x12?\n\x10\x64\x65vice_config_id\x18\x03 \x01(\x0b\x32%.chromiumos.config.api.DeviceConfigId\x12\x30\n\x03ssh\x18\x02 \x01(\x0b\x32#.chromiumos.test.lab.api.IpEndpoint\x12-\n\x05servo\x18\x04 \x01(\x0b\x32\x1e.chromiumos.test.lab.api.Servo\x12\x35\n\tchameleon\x18\x05 \x01(\x0b\x32\".chromiumos.test.lab.api.Chameleon\x12)\n\x03rpm\x18\x06 \x01(\x0b\x32\x1c.chromiumos.test.lab.api.RPM\x12\x41\n\x10\x65xternal_cameras\x18\x07 \x03(\x0b\x32\'.chromiumos.test.lab.api.ExternalCamera\x12-\n\x05\x61udio\x18\x08 \x01(\x0b\x32\x1e.chromiumos.test.lab.api.Audio\x12+\n\x04wifi\x18\t \x01(\x0b\x32\x1d.chromiumos.test.lab.api.Wifi\x12-\n\x05touch\x18\n \x01(\x0b\x32\x1e.chromiumos.test.lab.api.Touch\x12\x35\n\tcamerabox\x18\x0b \x01(\x0b\x32\".chromiumos.test.lab.api.Camerabox\x12.\n\x06\x63\x61\x62les\x18\x0c \x03(\x0b\x32\x1e.chromiumos.test.lab.api.Cable\x12\x33\n\x08\x63\x65llular\x18\r \x01(\x0b\x32!.chromiumos.test.lab.api.CellularJ\x04\x08\x01\x10\x02\x1a\t\n\x07\x41ndroidB\n\n\x08\x64ut_type\"\x8f\x01\n\x0b\x44utTopology\x12\x33\n\x02id\x18\x03 \x01(\x0b\x32\'.chromiumos.test.lab.api.DutTopology.Id\x12*\n\x04\x64uts\x18\x04 \x03(\x0b\x32\x1c.chromiumos.test.lab.api.Dut\x1a\x13\n\x02Id\x12\r\n\x05value\x18\x01 \x01(\tJ\x04\x08\x01\x10\x02J\x04\x08\x02\x10\x03\")\n\x05\x41udio\x12\x11\n\taudio_box\x18\x01 \x01(\x08\x12\r\n\x05\x61trus\x18\x02 \x01(\x08\"\x95\x01\n\x05\x43\x61\x62le\x12\x31\n\x04type\x18\x01 \x01(\x0e\x32#.chromiumos.test.lab.api.Cable.Type\"Y\n\x04Type\x12\x14\n\x10TYPE_UNSPECIFIED\x10\x00\x12\r\n\tAUDIOJACK\x10\x01\x12\x0c\n\x08USBAUDIO\x10\x02\x12\x0f\n\x0bUSBPRINTING\x10\x03\x12\r\n\tHDMIAUDIO\x10\x04\"C\n\x0b\x43\x61\x63heServer\x12\x34\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0b\x32#.chromiumos.test.lab.api.IpEndpoint\"}\n\tCamerabox\x12\x39\n\x06\x66\x61\x63ing\x18\x01 \x01(\x0e\x32).chromiumos.test.lab.api.Camerabox.Facing\"5\n\x06\x46\x61\x63ing\x12\x16\n\x12\x46\x41\x43ING_UNSPECIFIED\x10\x00\x12\x08\n\x04\x42\x41\x43K\x10\x01\x12\t\n\x05\x46RONT\x10\x02\"\x92\x01\n\x08\x43\x65llular\x12=\n\toperators\x18\x01 \x03(\x0e\x32*.chromiumos.test.lab.api.Cellular.Operator\"G\n\x08Operator\x12\x18\n\x14OPERATOR_UNSPECIFIED\x10\x00\x12\x07\n\x03\x41TT\x10\x01\x12\x0b\n\x07VERIZON\x10\x02\x12\x0b\n\x07TMOBILE\x10\x03\"\xf2\x01\n\tChameleon\x12\x42\n\x0bperipherals\x18\x01 \x03(\x0e\x32-.chromiumos.test.lab.api.Chameleon.Peripheral\x12\x13\n\x0b\x61udio_board\x18\x02 \x01(\x08\"\x8b\x01\n\nPeripheral\x12\x1a\n\x16PREIPHERAL_UNSPECIFIED\x10\x00\x12\n\n\x06\x42T_HID\x10\x01\x12\x06\n\x02\x44P\x10\x02\x12\x0b\n\x07\x44P_HDMI\x10\x03\x12\x07\n\x03VGA\x10\x04\x12\x08\n\x04HDMI\x10\x05\x12\x0e\n\nBT_BLE_HID\x10\x06\x12\x10\n\x0c\x42T_A2DP_SINK\x10\x07\x12\x0b\n\x07\x42T_PEER\x10\x08\"\x83\x01\n\x0e\x45xternalCamera\x12:\n\x04type\x18\x01 \x01(\x0e\x32,.chromiumos.test.lab.api.ExternalCamera.Type\"5\n\x04Type\x12\x14\n\x10TYPE_UNSPECIFIED\x10\x00\x12\n\n\x06HUDDLY\x10\x01\x12\x0b\n\x07PTZPRO2\x10\x02\"\x16\n\x03RPM\x12\x0f\n\x07present\x18\x01 \x01(\x08\"U\n\x05Servo\x12\x0f\n\x07present\x18\x01 \x01(\x08\x12;\n\x0eservod_address\x18\x02 \x01(\x0b\x32#.chromiumos.test.lab.api.IpEndpoint\"\x15\n\x05Touch\x12\x0c\n\x04mimo\x18\x01 \x01(\x08\"\xe6\x01\n\x04Wifi\x12>\n\x0b\x65nvironment\x18\x01 \x01(\x0e\x32).chromiumos.test.lab.api.Wifi.Environment\x12\x35\n\x07\x61ntenna\x18\x02 \x01(\x0b\x32$.chromiumos.test.lab.api.WifiAntenna\"g\n\x0b\x45nvironment\x12\x1b\n\x17\x45NVIRONMENT_UNSPECIFIED\x10\x00\x12\x0c\n\x08STANDARD\x10\x01\x12\r\n\tWIFI_CELL\x10\x02\x12\t\n\x05\x43HAOS\x10\x03\x12\x13\n\x0fROUTER_802_11AX\x10\x04\"\x95\x01\n\x0bWifiAntenna\x12\x43\n\nconnection\x18\x01 \x01(\x0e\x32/.chromiumos.test.lab.api.WifiAntenna.Connection\"A\n\nConnection\x12\x1a\n\x16\x43ONNECTION_UNSPECIFIED\x10\x00\x12\x0e\n\nCONDUCTIVE\x10\x01\x12\x07\n\x03OTA\x10\x02\x42\x33Z1go.chromium.org/chromiumos/config/go/test/lab/apib\x06proto3'
+  serialized_pb=b'\n!chromiumos/test/lab/api/dut.proto\x12\x17\x63hromiumos.test.lab.api\x1a,chromiumos/config/api/device_config_id.proto\x1a)chromiumos/test/lab/api/ip_endpoint.proto\"\xe3\x08\n\x03\x44ut\x12+\n\x02id\x18\x01 \x01(\x0b\x32\x1f.chromiumos.test.lab.api.Dut.Id\x12\x39\n\x08\x63hromeos\x18\x02 \x01(\x0b\x32%.chromiumos.test.lab.api.Dut.ChromeOSH\x00\x12\x37\n\x07\x61ndroid\x18\x03 \x01(\x0b\x32$.chromiumos.test.lab.api.Dut.AndroidH\x00\x12:\n\x0c\x63\x61\x63he_server\x18\x04 \x01(\x0b\x32$.chromiumos.test.lab.api.CacheServer\x1a\x13\n\x02Id\x12\r\n\x05value\x18\x01 \x01(\t\x1a\xb4\x05\n\x08\x43hromeOS\x12?\n\x10\x64\x65vice_config_id\x18\x03 \x01(\x0b\x32%.chromiumos.config.api.DeviceConfigId\x12\x30\n\x03ssh\x18\x02 \x01(\x0b\x32#.chromiumos.test.lab.api.IpEndpoint\x12\x34\n\tdut_model\x18\x0e \x01(\x0b\x32!.chromiumos.test.lab.api.DutModel\x12-\n\x05servo\x18\x04 \x01(\x0b\x32\x1e.chromiumos.test.lab.api.Servo\x12\x35\n\tchameleon\x18\x05 \x01(\x0b\x32\".chromiumos.test.lab.api.Chameleon\x12)\n\x03rpm\x18\x06 \x01(\x0b\x32\x1c.chromiumos.test.lab.api.RPM\x12\x41\n\x10\x65xternal_cameras\x18\x07 \x03(\x0b\x32\'.chromiumos.test.lab.api.ExternalCamera\x12-\n\x05\x61udio\x18\x08 \x01(\x0b\x32\x1e.chromiumos.test.lab.api.Audio\x12+\n\x04wifi\x18\t \x01(\x0b\x32\x1d.chromiumos.test.lab.api.Wifi\x12-\n\x05touch\x18\n \x01(\x0b\x32\x1e.chromiumos.test.lab.api.Touch\x12\x35\n\tcamerabox\x18\x0b \x01(\x0b\x32\".chromiumos.test.lab.api.Camerabox\x12.\n\x06\x63\x61\x62les\x18\x0c \x03(\x0b\x32\x1e.chromiumos.test.lab.api.Cable\x12\x33\n\x08\x63\x65llular\x18\r \x01(\x0b\x32!.chromiumos.test.lab.api.CellularJ\x04\x08\x01\x10\x02\x1a\xa6\x01\n\x07\x41ndroid\x12@\n\x13\x61ssociated_hostname\x18\x01 \x01(\x0b\x32#.chromiumos.test.lab.api.IpEndpoint\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x15\n\rserial_number\x18\x03 \x01(\t\x12\x34\n\tdut_model\x18\x04 \x01(\x0b\x32!.chromiumos.test.lab.api.DutModelB\n\n\x08\x64ut_type\"4\n\x08\x44utModel\x12\x14\n\x0c\x62uild_target\x18\x01 \x01(\t\x12\x12\n\nmodel_name\x18\x02 \x01(\t\"\x8f\x01\n\x0b\x44utTopology\x12\x33\n\x02id\x18\x03 \x01(\x0b\x32\'.chromiumos.test.lab.api.DutTopology.Id\x12*\n\x04\x64uts\x18\x04 \x03(\x0b\x32\x1c.chromiumos.test.lab.api.Dut\x1a\x13\n\x02Id\x12\r\n\x05value\x18\x01 \x01(\tJ\x04\x08\x01\x10\x02J\x04\x08\x02\x10\x03\")\n\x05\x41udio\x12\x11\n\taudio_box\x18\x01 \x01(\x08\x12\r\n\x05\x61trus\x18\x02 \x01(\x08\"\x95\x01\n\x05\x43\x61\x62le\x12\x31\n\x04type\x18\x01 \x01(\x0e\x32#.chromiumos.test.lab.api.Cable.Type\"Y\n\x04Type\x12\x14\n\x10TYPE_UNSPECIFIED\x10\x00\x12\r\n\tAUDIOJACK\x10\x01\x12\x0c\n\x08USBAUDIO\x10\x02\x12\x0f\n\x0bUSBPRINTING\x10\x03\x12\r\n\tHDMIAUDIO\x10\x04\"C\n\x0b\x43\x61\x63heServer\x12\x34\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0b\x32#.chromiumos.test.lab.api.IpEndpoint\"}\n\tCamerabox\x12\x39\n\x06\x66\x61\x63ing\x18\x01 \x01(\x0e\x32).chromiumos.test.lab.api.Camerabox.Facing\"5\n\x06\x46\x61\x63ing\x12\x16\n\x12\x46\x41\x43ING_UNSPECIFIED\x10\x00\x12\x08\n\x04\x42\x41\x43K\x10\x01\x12\t\n\x05\x46RONT\x10\x02\"\x92\x01\n\x08\x43\x65llular\x12=\n\toperators\x18\x01 \x03(\x0e\x32*.chromiumos.test.lab.api.Cellular.Operator\"G\n\x08Operator\x12\x18\n\x14OPERATOR_UNSPECIFIED\x10\x00\x12\x07\n\x03\x41TT\x10\x01\x12\x0b\n\x07VERIZON\x10\x02\x12\x0b\n\x07TMOBILE\x10\x03\"\xf2\x01\n\tChameleon\x12\x42\n\x0bperipherals\x18\x01 \x03(\x0e\x32-.chromiumos.test.lab.api.Chameleon.Peripheral\x12\x13\n\x0b\x61udio_board\x18\x02 \x01(\x08\"\x8b\x01\n\nPeripheral\x12\x1a\n\x16PREIPHERAL_UNSPECIFIED\x10\x00\x12\n\n\x06\x42T_HID\x10\x01\x12\x06\n\x02\x44P\x10\x02\x12\x0b\n\x07\x44P_HDMI\x10\x03\x12\x07\n\x03VGA\x10\x04\x12\x08\n\x04HDMI\x10\x05\x12\x0e\n\nBT_BLE_HID\x10\x06\x12\x10\n\x0c\x42T_A2DP_SINK\x10\x07\x12\x0b\n\x07\x42T_PEER\x10\x08\"\x83\x01\n\x0e\x45xternalCamera\x12:\n\x04type\x18\x01 \x01(\x0e\x32,.chromiumos.test.lab.api.ExternalCamera.Type\"5\n\x04Type\x12\x14\n\x10TYPE_UNSPECIFIED\x10\x00\x12\n\n\x06HUDDLY\x10\x01\x12\x0b\n\x07PTZPRO2\x10\x02\"\x16\n\x03RPM\x12\x0f\n\x07present\x18\x01 \x01(\x08\"U\n\x05Servo\x12\x0f\n\x07present\x18\x01 \x01(\x08\x12;\n\x0eservod_address\x18\x02 \x01(\x0b\x32#.chromiumos.test.lab.api.IpEndpoint\"\x15\n\x05Touch\x12\x0c\n\x04mimo\x18\x01 \x01(\x08\"\xe6\x01\n\x04Wifi\x12>\n\x0b\x65nvironment\x18\x01 \x01(\x0e\x32).chromiumos.test.lab.api.Wifi.Environment\x12\x35\n\x07\x61ntenna\x18\x02 \x01(\x0b\x32$.chromiumos.test.lab.api.WifiAntenna\"g\n\x0b\x45nvironment\x12\x1b\n\x17\x45NVIRONMENT_UNSPECIFIED\x10\x00\x12\x0c\n\x08STANDARD\x10\x01\x12\r\n\tWIFI_CELL\x10\x02\x12\t\n\x05\x43HAOS\x10\x03\x12\x13\n\x0fROUTER_802_11AX\x10\x04\"\x95\x01\n\x0bWifiAntenna\x12\x43\n\nconnection\x18\x01 \x01(\x0e\x32/.chromiumos.test.lab.api.WifiAntenna.Connection\"A\n\nConnection\x12\x1a\n\x16\x43ONNECTION_UNSPECIFIED\x10\x00\x12\x0e\n\nCONDUCTIVE\x10\x01\x12\x07\n\x03OTA\x10\x02\x42\x33Z1go.chromium.org/chromiumos/config/go/test/lab/apib\x06proto3'
   ,
   dependencies=[chromiumos_dot_config_dot_api_dot_device__config__id__pb2.DESCRIPTOR,chromiumos_dot_test_dot_lab_dot_api_dot_ip__endpoint__pb2.DESCRIPTOR,])
 
@@ -62,8 +62,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1315,
-  serialized_end=1404,
+  serialized_start=1581,
+  serialized_end=1670,
 )
 _sym_db.RegisterEnumDescriptor(_CABLE_TYPE)
 
@@ -92,8 +92,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1547,
-  serialized_end=1600,
+  serialized_start=1813,
+  serialized_end=1866,
 )
 _sym_db.RegisterEnumDescriptor(_CAMERABOX_FACING)
 
@@ -127,8 +127,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1678,
-  serialized_end=1749,
+  serialized_start=1944,
+  serialized_end=2015,
 )
 _sym_db.RegisterEnumDescriptor(_CELLULAR_OPERATOR)
 
@@ -187,8 +187,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1855,
-  serialized_end=1994,
+  serialized_start=2121,
+  serialized_end=2260,
 )
 _sym_db.RegisterEnumDescriptor(_CHAMELEON_PERIPHERAL)
 
@@ -217,8 +217,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2075,
-  serialized_end=2128,
+  serialized_start=2341,
+  serialized_end=2394,
 )
 _sym_db.RegisterEnumDescriptor(_EXTERNALCAMERA_TYPE)
 
@@ -257,8 +257,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2392,
-  serialized_end=2495,
+  serialized_start=2658,
+  serialized_end=2761,
 )
 _sym_db.RegisterEnumDescriptor(_WIFI_ENVIRONMENT)
 
@@ -287,8 +287,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2582,
-  serialized_end=2647,
+  serialized_start=2848,
+  serialized_end=2913,
 )
 _sym_db.RegisterEnumDescriptor(_WIFIANTENNA_CONNECTION)
 
@@ -347,70 +347,77 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='servo', full_name='chromiumos.test.lab.api.Dut.ChromeOS.servo', index=2,
+      name='dut_model', full_name='chromiumos.test.lab.api.Dut.ChromeOS.dut_model', index=2,
+      number=14, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='servo', full_name='chromiumos.test.lab.api.Dut.ChromeOS.servo', index=3,
       number=4, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='chameleon', full_name='chromiumos.test.lab.api.Dut.ChromeOS.chameleon', index=3,
+      name='chameleon', full_name='chromiumos.test.lab.api.Dut.ChromeOS.chameleon', index=4,
       number=5, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='rpm', full_name='chromiumos.test.lab.api.Dut.ChromeOS.rpm', index=4,
+      name='rpm', full_name='chromiumos.test.lab.api.Dut.ChromeOS.rpm', index=5,
       number=6, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='external_cameras', full_name='chromiumos.test.lab.api.Dut.ChromeOS.external_cameras', index=5,
+      name='external_cameras', full_name='chromiumos.test.lab.api.Dut.ChromeOS.external_cameras', index=6,
       number=7, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='audio', full_name='chromiumos.test.lab.api.Dut.ChromeOS.audio', index=6,
+      name='audio', full_name='chromiumos.test.lab.api.Dut.ChromeOS.audio', index=7,
       number=8, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='wifi', full_name='chromiumos.test.lab.api.Dut.ChromeOS.wifi', index=7,
+      name='wifi', full_name='chromiumos.test.lab.api.Dut.ChromeOS.wifi', index=8,
       number=9, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='touch', full_name='chromiumos.test.lab.api.Dut.ChromeOS.touch', index=8,
+      name='touch', full_name='chromiumos.test.lab.api.Dut.ChromeOS.touch', index=9,
       number=10, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='camerabox', full_name='chromiumos.test.lab.api.Dut.ChromeOS.camerabox', index=9,
+      name='camerabox', full_name='chromiumos.test.lab.api.Dut.ChromeOS.camerabox', index=10,
       number=11, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='cables', full_name='chromiumos.test.lab.api.Dut.ChromeOS.cables', index=10,
+      name='cables', full_name='chromiumos.test.lab.api.Dut.ChromeOS.cables', index=11,
       number=12, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='cellular', full_name='chromiumos.test.lab.api.Dut.ChromeOS.cellular', index=11,
+      name='cellular', full_name='chromiumos.test.lab.api.Dut.ChromeOS.cellular', index=12,
       number=13, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
@@ -429,7 +436,7 @@
   oneofs=[
   ],
   serialized_start=402,
-  serialized_end=1040,
+  serialized_end=1094,
 )
 
 _DUT_ANDROID = _descriptor.Descriptor(
@@ -440,6 +447,34 @@
   containing_type=None,
   create_key=_descriptor._internal_create_key,
   fields=[
+    _descriptor.FieldDescriptor(
+      name='associated_hostname', full_name='chromiumos.test.lab.api.Dut.Android.associated_hostname', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='name', full_name='chromiumos.test.lab.api.Dut.Android.name', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='serial_number', full_name='chromiumos.test.lab.api.Dut.Android.serial_number', index=2,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='dut_model', full_name='chromiumos.test.lab.api.Dut.Android.dut_model', index=3,
+      number=4, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -452,8 +487,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1042,
-  serialized_end=1051,
+  serialized_start=1097,
+  serialized_end=1263,
 )
 
 _DUT = _descriptor.Descriptor(
@@ -487,7 +522,7 @@
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
       name='cache_server', full_name='chromiumos.test.lab.api.Dut.cache_server', index=3,
-      number=14, type=11, cpp_type=10, label=1,
+      number=4, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
@@ -510,7 +545,46 @@
     fields=[]),
   ],
   serialized_start=152,
-  serialized_end=1063,
+  serialized_end=1275,
+)
+
+
+_DUTMODEL = _descriptor.Descriptor(
+  name='DutModel',
+  full_name='chromiumos.test.lab.api.DutModel',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='build_target', full_name='chromiumos.test.lab.api.DutModel.build_target', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='model_name', full_name='chromiumos.test.lab.api.DutModel.model_name', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1277,
+  serialized_end=1329,
 )
 
 
@@ -579,8 +653,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1066,
-  serialized_end=1209,
+  serialized_start=1332,
+  serialized_end=1475,
 )
 
 
@@ -618,8 +692,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1211,
-  serialized_end=1252,
+  serialized_start=1477,
+  serialized_end=1518,
 )
 
 
@@ -651,8 +725,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1255,
-  serialized_end=1404,
+  serialized_start=1521,
+  serialized_end=1670,
 )
 
 
@@ -683,8 +757,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1406,
-  serialized_end=1473,
+  serialized_start=1672,
+  serialized_end=1739,
 )
 
 
@@ -716,8 +790,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1475,
-  serialized_end=1600,
+  serialized_start=1741,
+  serialized_end=1866,
 )
 
 
@@ -749,8 +823,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1603,
-  serialized_end=1749,
+  serialized_start=1869,
+  serialized_end=2015,
 )
 
 
@@ -789,8 +863,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1752,
-  serialized_end=1994,
+  serialized_start=2018,
+  serialized_end=2260,
 )
 
 
@@ -822,8 +896,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1997,
-  serialized_end=2128,
+  serialized_start=2263,
+  serialized_end=2394,
 )
 
 
@@ -854,8 +928,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2130,
-  serialized_end=2152,
+  serialized_start=2396,
+  serialized_end=2418,
 )
 
 
@@ -893,8 +967,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2154,
-  serialized_end=2239,
+  serialized_start=2420,
+  serialized_end=2505,
 )
 
 
@@ -925,8 +999,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2241,
-  serialized_end=2262,
+  serialized_start=2507,
+  serialized_end=2528,
 )
 
 
@@ -965,8 +1039,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2265,
-  serialized_end=2495,
+  serialized_start=2531,
+  serialized_end=2761,
 )
 
 
@@ -998,13 +1072,14 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2498,
-  serialized_end=2647,
+  serialized_start=2764,
+  serialized_end=2913,
 )
 
 _DUT_ID.containing_type = _DUT
 _DUT_CHROMEOS.fields_by_name['device_config_id'].message_type = chromiumos_dot_config_dot_api_dot_device__config__id__pb2._DEVICECONFIGID
 _DUT_CHROMEOS.fields_by_name['ssh'].message_type = chromiumos_dot_test_dot_lab_dot_api_dot_ip__endpoint__pb2._IPENDPOINT
+_DUT_CHROMEOS.fields_by_name['dut_model'].message_type = _DUTMODEL
 _DUT_CHROMEOS.fields_by_name['servo'].message_type = _SERVO
 _DUT_CHROMEOS.fields_by_name['chameleon'].message_type = _CHAMELEON
 _DUT_CHROMEOS.fields_by_name['rpm'].message_type = _RPM
@@ -1016,6 +1091,8 @@
 _DUT_CHROMEOS.fields_by_name['cables'].message_type = _CABLE
 _DUT_CHROMEOS.fields_by_name['cellular'].message_type = _CELLULAR
 _DUT_CHROMEOS.containing_type = _DUT
+_DUT_ANDROID.fields_by_name['associated_hostname'].message_type = chromiumos_dot_test_dot_lab_dot_api_dot_ip__endpoint__pb2._IPENDPOINT
+_DUT_ANDROID.fields_by_name['dut_model'].message_type = _DUTMODEL
 _DUT_ANDROID.containing_type = _DUT
 _DUT.fields_by_name['id'].message_type = _DUT_ID
 _DUT.fields_by_name['chromeos'].message_type = _DUT_CHROMEOS
@@ -1048,6 +1125,7 @@
 _WIFIANTENNA.fields_by_name['connection'].enum_type = _WIFIANTENNA_CONNECTION
 _WIFIANTENNA_CONNECTION.containing_type = _WIFIANTENNA
 DESCRIPTOR.message_types_by_name['Dut'] = _DUT
+DESCRIPTOR.message_types_by_name['DutModel'] = _DUTMODEL
 DESCRIPTOR.message_types_by_name['DutTopology'] = _DUTTOPOLOGY
 DESCRIPTOR.message_types_by_name['Audio'] = _AUDIO
 DESCRIPTOR.message_types_by_name['Cable'] = _CABLE
@@ -1094,6 +1172,13 @@
 _sym_db.RegisterMessage(Dut.ChromeOS)
 _sym_db.RegisterMessage(Dut.Android)
 
+DutModel = _reflection.GeneratedProtocolMessageType('DutModel', (_message.Message,), {
+  'DESCRIPTOR' : _DUTMODEL,
+  '__module__' : 'chromiumos.test.lab.api.dut_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.lab.api.DutModel)
+  })
+_sym_db.RegisterMessage(DutModel)
+
 DutTopology = _reflection.GeneratedProtocolMessageType('DutTopology', (_message.Message,), {
 
   'Id' : _reflection.GeneratedProtocolMessageType('Id', (_message.Message,), {
diff --git a/api/gen/chromiumos/test/lab/api/tape_service_pb2.py b/api/gen/chromiumos/test/lab/api/tape_service_pb2.py
new file mode 100644
index 0000000..2258d56
--- /dev/null
+++ b/api/gen/chromiumos/test/lab/api/tape_service_pb2.py
@@ -0,0 +1,158 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: chromiumos/test/lab/api/tape_service.proto
+"""Generated protocol buffer code."""
+from chromite.third_party.google.protobuf import descriptor as _descriptor
+from chromite.third_party.google.protobuf import message as _message
+from chromite.third_party.google.protobuf import reflection as _reflection
+from chromite.third_party.google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='chromiumos/test/lab/api/tape_service.proto',
+  package='chromiumos.test.lab.api',
+  syntax='proto3',
+  serialized_options=b'Z1go.chromium.org/chromiumos/config/go/test/lab/api',
+  create_key=_descriptor._internal_create_key,
+  serialized_pb=b'\n*chromiumos/test/lab/api/tape_service.proto\x12\x17\x63hromiumos.test.lab.api\"s\n\x0f\x43\x61llTapeRequest\x12\x18\n\x10request_endpoint\x18\x01 \x01(\t\x12\x16\n\x0erequest_method\x18\x02 \x01(\t\x12\x17\n\x0frequest_timeout\x18\x03 \x01(\x05\x12\x15\n\rpayload_bytes\x18\x04 \x01(\x0c\")\n\x10\x43\x61llTapeResponse\x12\x15\n\rpayload_bytes\x18\x01 \x01(\x0c\x32n\n\x0bTapeService\x12_\n\x08\x43\x61llTape\x12(.chromiumos.test.lab.api.CallTapeRequest\x1a).chromiumos.test.lab.api.CallTapeResponseB3Z1go.chromium.org/chromiumos/config/go/test/lab/apib\x06proto3'
+)
+
+
+
+
+_CALLTAPEREQUEST = _descriptor.Descriptor(
+  name='CallTapeRequest',
+  full_name='chromiumos.test.lab.api.CallTapeRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='request_endpoint', full_name='chromiumos.test.lab.api.CallTapeRequest.request_endpoint', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='request_method', full_name='chromiumos.test.lab.api.CallTapeRequest.request_method', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='request_timeout', full_name='chromiumos.test.lab.api.CallTapeRequest.request_timeout', index=2,
+      number=3, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='payload_bytes', full_name='chromiumos.test.lab.api.CallTapeRequest.payload_bytes', index=3,
+      number=4, type=12, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"",
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=71,
+  serialized_end=186,
+)
+
+
+_CALLTAPERESPONSE = _descriptor.Descriptor(
+  name='CallTapeResponse',
+  full_name='chromiumos.test.lab.api.CallTapeResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='payload_bytes', full_name='chromiumos.test.lab.api.CallTapeResponse.payload_bytes', index=0,
+      number=1, type=12, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"",
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=188,
+  serialized_end=229,
+)
+
+DESCRIPTOR.message_types_by_name['CallTapeRequest'] = _CALLTAPEREQUEST
+DESCRIPTOR.message_types_by_name['CallTapeResponse'] = _CALLTAPERESPONSE
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+CallTapeRequest = _reflection.GeneratedProtocolMessageType('CallTapeRequest', (_message.Message,), {
+  'DESCRIPTOR' : _CALLTAPEREQUEST,
+  '__module__' : 'chromiumos.test.lab.api.tape_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.lab.api.CallTapeRequest)
+  })
+_sym_db.RegisterMessage(CallTapeRequest)
+
+CallTapeResponse = _reflection.GeneratedProtocolMessageType('CallTapeResponse', (_message.Message,), {
+  'DESCRIPTOR' : _CALLTAPERESPONSE,
+  '__module__' : 'chromiumos.test.lab.api.tape_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.lab.api.CallTapeResponse)
+  })
+_sym_db.RegisterMessage(CallTapeResponse)
+
+
+DESCRIPTOR._options = None
+
+_TAPESERVICE = _descriptor.ServiceDescriptor(
+  name='TapeService',
+  full_name='chromiumos.test.lab.api.TapeService',
+  file=DESCRIPTOR,
+  index=0,
+  serialized_options=None,
+  create_key=_descriptor._internal_create_key,
+  serialized_start=231,
+  serialized_end=341,
+  methods=[
+  _descriptor.MethodDescriptor(
+    name='CallTape',
+    full_name='chromiumos.test.lab.api.TapeService.CallTape',
+    index=0,
+    containing_service=None,
+    input_type=_CALLTAPEREQUEST,
+    output_type=_CALLTAPERESPONSE,
+    serialized_options=None,
+    create_key=_descriptor._internal_create_key,
+  ),
+])
+_sym_db.RegisterServiceDescriptor(_TAPESERVICE)
+
+DESCRIPTOR.services_by_name['TapeService'] = _TAPESERVICE
+
+# @@protoc_insertion_point(module_scope)
diff --git a/api/gen/chromiumos/test/plan/source_test_plan_pb2.py b/api/gen/chromiumos/test/plan/source_test_plan_pb2.py
index 813d6db..c7b96e9 100644
--- a/api/gen/chromiumos/test/plan/source_test_plan_pb2.py
+++ b/api/gen/chromiumos/test/plan/source_test_plan_pb2.py
@@ -19,41 +19,11 @@
   syntax='proto3',
   serialized_options=b'Z.go.chromium.org/chromiumos/config/go/test/plan',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n+chromiumos/test/plan/source_test_plan.proto\x12\x14\x63hromiumos.test.plan\"\x99\x0c\n\x0eSourceTestPlan\x12[\n\x19\x65nabled_test_environments\x18\x01 \x03(\x0e\x32\x34.chromiumos.test.plan.SourceTestPlan.TestEnvironmentB\x02\x18\x01\x12\x14\n\x0cpath_regexps\x18\x02 \x03(\t\x12\x1c\n\x14path_regexp_excludes\x18\x03 \x03(\t\x12[\n\x18test_plan_starlark_files\x18\x0f \x03(\x0b\x32\x39.chromiumos.test.plan.SourceTestPlan.TestPlanStarlarkFile\x12\x15\n\ttest_tags\x18\x04 \x03(\tB\x02\x18\x01\x12\x1d\n\x11test_tag_excludes\x18\x05 \x03(\tB\x02\x18\x01\x12K\n\x0crequirements\x18\r \x01(\x0b\x32\x31.chromiumos.test.plan.SourceTestPlan.RequirementsB\x02\x18\x01\x1a\x32\n\x14TestPlanStarlarkFile\x12\x0c\n\x04repo\x18\x01 \x01(\t\x12\x0c\n\x04path\x18\x02 \x01(\t\x1a\x8b\x08\n\x0cRequirements\x12Y\n\x0fkernel_versions\x18\x01 \x01(\x0b\x32@.chromiumos.test.plan.SourceTestPlan.Requirements.KernelVersions\x12S\n\x0csoc_families\x18\x02 \x01(\x0b\x32=.chromiumos.test.plan.SourceTestPlan.Requirements.SocFamilies\x12V\n\rarchitectures\x18\x03 \x01(\x0b\x32?.chromiumos.test.plan.SourceTestPlan.Requirements.Architectures\x12S\n\x0c\x61rc_versions\x18\x04 \x01(\x0b\x32=.chromiumos.test.plan.SourceTestPlan.Requirements.ArcVersions\x12R\n\x0b\x66ingerprint\x18\x05 \x01(\x0b\x32=.chromiumos.test.plan.SourceTestPlan.Requirements.Fingerprint\x12N\n\tparallels\x18\x06 \x01(\x0b\x32;.chromiumos.test.plan.SourceTestPlan.Requirements.Parallels\x12Y\n\x0f\x63hromeos_config\x18\x07 \x01(\x0b\x32@.chromiumos.test.plan.SourceTestPlan.Requirements.ChromeOSConfig\x12\x62\n\x14\x66irmware_ro_versions\x18\x08 \x01(\x0b\x32\x44.chromiumos.test.plan.SourceTestPlan.Requirements.FirmwareROVersions\x1a\x10\n\x0eKernelVersions\x1a\r\n\x0bSocFamilies\x1a\x0f\n\rArchitectures\x1a\r\n\x0b\x41rcVersions\x1a\r\n\x0b\x46ingerprint\x1a\x0b\n\tParallels\x1a\x10\n\x0e\x43hromeOSConfig\x1a\xcb\x01\n\x12\x46irmwareROVersions\x12z\n\x14program_to_milestone\x18\x01 \x03(\x0b\x32\\.chromiumos.test.plan.SourceTestPlan.Requirements.FirmwareROVersions.ProgramToMilestoneEntry\x1a\x39\n\x17ProgramToMilestoneEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\"N\n\x0fTestEnvironment\x12 \n\x1cTEST_ENVIRONMENT_UNSPECIFIED\x10\x00\x12\x0c\n\x08HARDWARE\x10\x01\x12\x0b\n\x07VIRTUAL\x10\x02J\x04\x08\x06\x10\rB0Z.go.chromium.org/chromiumos/config/go/test/planb\x06proto3'
+  serialized_pb=b'\n+chromiumos/test/plan/source_test_plan.proto\x12\x14\x63hromiumos.test.plan\"\xf2\x01\n\x0eSourceTestPlan\x12\x14\n\x0cpath_regexps\x18\x02 \x03(\t\x12\x1c\n\x14path_regexp_excludes\x18\x03 \x03(\t\x12[\n\x18test_plan_starlark_files\x18\x0f \x03(\x0b\x32\x39.chromiumos.test.plan.SourceTestPlan.TestPlanStarlarkFile\x1a\x43\n\x14TestPlanStarlarkFile\x12\x0c\n\x04host\x18\x01 \x01(\t\x12\x0f\n\x07project\x18\x02 \x01(\t\x12\x0c\n\x04path\x18\x03 \x01(\tJ\x04\x08\x01\x10\x02J\x04\x08\x04\x10\x0f\x42\x30Z.go.chromium.org/chromiumos/config/go/test/planb\x06proto3'
 )
 
 
 
-_SOURCETESTPLAN_TESTENVIRONMENT = _descriptor.EnumDescriptor(
-  name='TestEnvironment',
-  full_name='chromiumos.test.plan.SourceTestPlan.TestEnvironment',
-  filename=None,
-  file=DESCRIPTOR,
-  create_key=_descriptor._internal_create_key,
-  values=[
-    _descriptor.EnumValueDescriptor(
-      name='TEST_ENVIRONMENT_UNSPECIFIED', index=0, number=0,
-      serialized_options=None,
-      type=None,
-      create_key=_descriptor._internal_create_key),
-    _descriptor.EnumValueDescriptor(
-      name='HARDWARE', index=1, number=1,
-      serialized_options=None,
-      type=None,
-      create_key=_descriptor._internal_create_key),
-    _descriptor.EnumValueDescriptor(
-      name='VIRTUAL', index=2, number=2,
-      serialized_options=None,
-      type=None,
-      create_key=_descriptor._internal_create_key),
-  ],
-  containing_type=None,
-  serialized_options=None,
-  serialized_start=1547,
-  serialized_end=1625,
-)
-_sym_db.RegisterEnumDescriptor(_SOURCETESTPLAN_TESTENVIRONMENT)
-
 
 _SOURCETESTPLAN_TESTPLANSTARLARKFILE = _descriptor.Descriptor(
   name='TestPlanStarlarkFile',
@@ -64,350 +34,40 @@
   create_key=_descriptor._internal_create_key,
   fields=[
     _descriptor.FieldDescriptor(
-      name='repo', full_name='chromiumos.test.plan.SourceTestPlan.TestPlanStarlarkFile.repo', index=0,
+      name='host', full_name='chromiumos.test.plan.SourceTestPlan.TestPlanStarlarkFile.host', index=0,
       number=1, type=9, cpp_type=9, label=1,
       has_default_value=False, default_value=b"".decode('utf-8'),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='path', full_name='chromiumos.test.plan.SourceTestPlan.TestPlanStarlarkFile.path', index=1,
+      name='project', full_name='chromiumos.test.plan.SourceTestPlan.TestPlanStarlarkFile.project', index=1,
       number=2, type=9, cpp_type=9, label=1,
       has_default_value=False, default_value=b"".decode('utf-8'),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=457,
-  serialized_end=507,
-)
-
-_SOURCETESTPLAN_REQUIREMENTS_KERNELVERSIONS = _descriptor.Descriptor(
-  name='KernelVersions',
-  full_name='chromiumos.test.plan.SourceTestPlan.Requirements.KernelVersions',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  create_key=_descriptor._internal_create_key,
-  fields=[
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1230,
-  serialized_end=1246,
-)
-
-_SOURCETESTPLAN_REQUIREMENTS_SOCFAMILIES = _descriptor.Descriptor(
-  name='SocFamilies',
-  full_name='chromiumos.test.plan.SourceTestPlan.Requirements.SocFamilies',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  create_key=_descriptor._internal_create_key,
-  fields=[
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1248,
-  serialized_end=1261,
-)
-
-_SOURCETESTPLAN_REQUIREMENTS_ARCHITECTURES = _descriptor.Descriptor(
-  name='Architectures',
-  full_name='chromiumos.test.plan.SourceTestPlan.Requirements.Architectures',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  create_key=_descriptor._internal_create_key,
-  fields=[
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1263,
-  serialized_end=1278,
-)
-
-_SOURCETESTPLAN_REQUIREMENTS_ARCVERSIONS = _descriptor.Descriptor(
-  name='ArcVersions',
-  full_name='chromiumos.test.plan.SourceTestPlan.Requirements.ArcVersions',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  create_key=_descriptor._internal_create_key,
-  fields=[
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1280,
-  serialized_end=1293,
-)
-
-_SOURCETESTPLAN_REQUIREMENTS_FINGERPRINT = _descriptor.Descriptor(
-  name='Fingerprint',
-  full_name='chromiumos.test.plan.SourceTestPlan.Requirements.Fingerprint',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  create_key=_descriptor._internal_create_key,
-  fields=[
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1295,
-  serialized_end=1308,
-)
-
-_SOURCETESTPLAN_REQUIREMENTS_PARALLELS = _descriptor.Descriptor(
-  name='Parallels',
-  full_name='chromiumos.test.plan.SourceTestPlan.Requirements.Parallels',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  create_key=_descriptor._internal_create_key,
-  fields=[
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1310,
-  serialized_end=1321,
-)
-
-_SOURCETESTPLAN_REQUIREMENTS_CHROMEOSCONFIG = _descriptor.Descriptor(
-  name='ChromeOSConfig',
-  full_name='chromiumos.test.plan.SourceTestPlan.Requirements.ChromeOSConfig',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  create_key=_descriptor._internal_create_key,
-  fields=[
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1323,
-  serialized_end=1339,
-)
-
-_SOURCETESTPLAN_REQUIREMENTS_FIRMWAREROVERSIONS_PROGRAMTOMILESTONEENTRY = _descriptor.Descriptor(
-  name='ProgramToMilestoneEntry',
-  full_name='chromiumos.test.plan.SourceTestPlan.Requirements.FirmwareROVersions.ProgramToMilestoneEntry',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  create_key=_descriptor._internal_create_key,
-  fields=[
     _descriptor.FieldDescriptor(
-      name='key', full_name='chromiumos.test.plan.SourceTestPlan.Requirements.FirmwareROVersions.ProgramToMilestoneEntry.key', index=0,
-      number=1, type=9, cpp_type=9, label=1,
+      name='path', full_name='chromiumos.test.plan.SourceTestPlan.TestPlanStarlarkFile.path', index=2,
+      number=3, type=9, cpp_type=9, label=1,
       has_default_value=False, default_value=b"".decode('utf-8'),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='value', full_name='chromiumos.test.plan.SourceTestPlan.Requirements.FirmwareROVersions.ProgramToMilestoneEntry.value', index=1,
-      number=2, type=5, cpp_type=1, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
   nested_types=[],
   enum_types=[
   ],
-  serialized_options=b'8\001',
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1488,
-  serialized_end=1545,
-)
-
-_SOURCETESTPLAN_REQUIREMENTS_FIRMWAREROVERSIONS = _descriptor.Descriptor(
-  name='FirmwareROVersions',
-  full_name='chromiumos.test.plan.SourceTestPlan.Requirements.FirmwareROVersions',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  create_key=_descriptor._internal_create_key,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='program_to_milestone', full_name='chromiumos.test.plan.SourceTestPlan.Requirements.FirmwareROVersions.program_to_milestone', index=0,
-      number=1, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-  ],
-  extensions=[
-  ],
-  nested_types=[_SOURCETESTPLAN_REQUIREMENTS_FIRMWAREROVERSIONS_PROGRAMTOMILESTONEENTRY, ],
-  enum_types=[
-  ],
   serialized_options=None,
   is_extendable=False,
   syntax='proto3',
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1342,
-  serialized_end=1545,
-)
-
-_SOURCETESTPLAN_REQUIREMENTS = _descriptor.Descriptor(
-  name='Requirements',
-  full_name='chromiumos.test.plan.SourceTestPlan.Requirements',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  create_key=_descriptor._internal_create_key,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='kernel_versions', full_name='chromiumos.test.plan.SourceTestPlan.Requirements.kernel_versions', index=0,
-      number=1, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='soc_families', full_name='chromiumos.test.plan.SourceTestPlan.Requirements.soc_families', index=1,
-      number=2, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='architectures', full_name='chromiumos.test.plan.SourceTestPlan.Requirements.architectures', index=2,
-      number=3, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='arc_versions', full_name='chromiumos.test.plan.SourceTestPlan.Requirements.arc_versions', index=3,
-      number=4, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='fingerprint', full_name='chromiumos.test.plan.SourceTestPlan.Requirements.fingerprint', index=4,
-      number=5, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='parallels', full_name='chromiumos.test.plan.SourceTestPlan.Requirements.parallels', index=5,
-      number=6, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='chromeos_config', full_name='chromiumos.test.plan.SourceTestPlan.Requirements.chromeos_config', index=6,
-      number=7, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='firmware_ro_versions', full_name='chromiumos.test.plan.SourceTestPlan.Requirements.firmware_ro_versions', index=7,
-      number=8, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-  ],
-  extensions=[
-  ],
-  nested_types=[_SOURCETESTPLAN_REQUIREMENTS_KERNELVERSIONS, _SOURCETESTPLAN_REQUIREMENTS_SOCFAMILIES, _SOURCETESTPLAN_REQUIREMENTS_ARCHITECTURES, _SOURCETESTPLAN_REQUIREMENTS_ARCVERSIONS, _SOURCETESTPLAN_REQUIREMENTS_FINGERPRINT, _SOURCETESTPLAN_REQUIREMENTS_PARALLELS, _SOURCETESTPLAN_REQUIREMENTS_CHROMEOSCONFIG, _SOURCETESTPLAN_REQUIREMENTS_FIRMWAREROVERSIONS, ],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=510,
-  serialized_end=1545,
+  serialized_start=233,
+  serialized_end=300,
 )
 
 _SOURCETESTPLAN = _descriptor.Descriptor(
@@ -419,60 +79,31 @@
   create_key=_descriptor._internal_create_key,
   fields=[
     _descriptor.FieldDescriptor(
-      name='enabled_test_environments', full_name='chromiumos.test.plan.SourceTestPlan.enabled_test_environments', index=0,
-      number=1, type=14, cpp_type=8, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=b'\030\001', file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='path_regexps', full_name='chromiumos.test.plan.SourceTestPlan.path_regexps', index=1,
+      name='path_regexps', full_name='chromiumos.test.plan.SourceTestPlan.path_regexps', index=0,
       number=2, type=9, cpp_type=9, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='path_regexp_excludes', full_name='chromiumos.test.plan.SourceTestPlan.path_regexp_excludes', index=2,
+      name='path_regexp_excludes', full_name='chromiumos.test.plan.SourceTestPlan.path_regexp_excludes', index=1,
       number=3, type=9, cpp_type=9, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='test_plan_starlark_files', full_name='chromiumos.test.plan.SourceTestPlan.test_plan_starlark_files', index=3,
+      name='test_plan_starlark_files', full_name='chromiumos.test.plan.SourceTestPlan.test_plan_starlark_files', index=2,
       number=15, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='test_tags', full_name='chromiumos.test.plan.SourceTestPlan.test_tags', index=4,
-      number=4, type=9, cpp_type=9, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=b'\030\001', file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='test_tag_excludes', full_name='chromiumos.test.plan.SourceTestPlan.test_tag_excludes', index=5,
-      number=5, type=9, cpp_type=9, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=b'\030\001', file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
-    _descriptor.FieldDescriptor(
-      name='requirements', full_name='chromiumos.test.plan.SourceTestPlan.requirements', index=6,
-      number=13, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=b'\030\001', file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
-  nested_types=[_SOURCETESTPLAN_TESTPLANSTARLARKFILE, _SOURCETESTPLAN_REQUIREMENTS, ],
+  nested_types=[_SOURCETESTPLAN_TESTPLANSTARLARKFILE, ],
   enum_types=[
-    _SOURCETESTPLAN_TESTENVIRONMENT,
   ],
   serialized_options=None,
   is_extendable=False,
@@ -481,33 +112,11 @@
   oneofs=[
   ],
   serialized_start=70,
-  serialized_end=1631,
+  serialized_end=312,
 )
 
 _SOURCETESTPLAN_TESTPLANSTARLARKFILE.containing_type = _SOURCETESTPLAN
-_SOURCETESTPLAN_REQUIREMENTS_KERNELVERSIONS.containing_type = _SOURCETESTPLAN_REQUIREMENTS
-_SOURCETESTPLAN_REQUIREMENTS_SOCFAMILIES.containing_type = _SOURCETESTPLAN_REQUIREMENTS
-_SOURCETESTPLAN_REQUIREMENTS_ARCHITECTURES.containing_type = _SOURCETESTPLAN_REQUIREMENTS
-_SOURCETESTPLAN_REQUIREMENTS_ARCVERSIONS.containing_type = _SOURCETESTPLAN_REQUIREMENTS
-_SOURCETESTPLAN_REQUIREMENTS_FINGERPRINT.containing_type = _SOURCETESTPLAN_REQUIREMENTS
-_SOURCETESTPLAN_REQUIREMENTS_PARALLELS.containing_type = _SOURCETESTPLAN_REQUIREMENTS
-_SOURCETESTPLAN_REQUIREMENTS_CHROMEOSCONFIG.containing_type = _SOURCETESTPLAN_REQUIREMENTS
-_SOURCETESTPLAN_REQUIREMENTS_FIRMWAREROVERSIONS_PROGRAMTOMILESTONEENTRY.containing_type = _SOURCETESTPLAN_REQUIREMENTS_FIRMWAREROVERSIONS
-_SOURCETESTPLAN_REQUIREMENTS_FIRMWAREROVERSIONS.fields_by_name['program_to_milestone'].message_type = _SOURCETESTPLAN_REQUIREMENTS_FIRMWAREROVERSIONS_PROGRAMTOMILESTONEENTRY
-_SOURCETESTPLAN_REQUIREMENTS_FIRMWAREROVERSIONS.containing_type = _SOURCETESTPLAN_REQUIREMENTS
-_SOURCETESTPLAN_REQUIREMENTS.fields_by_name['kernel_versions'].message_type = _SOURCETESTPLAN_REQUIREMENTS_KERNELVERSIONS
-_SOURCETESTPLAN_REQUIREMENTS.fields_by_name['soc_families'].message_type = _SOURCETESTPLAN_REQUIREMENTS_SOCFAMILIES
-_SOURCETESTPLAN_REQUIREMENTS.fields_by_name['architectures'].message_type = _SOURCETESTPLAN_REQUIREMENTS_ARCHITECTURES
-_SOURCETESTPLAN_REQUIREMENTS.fields_by_name['arc_versions'].message_type = _SOURCETESTPLAN_REQUIREMENTS_ARCVERSIONS
-_SOURCETESTPLAN_REQUIREMENTS.fields_by_name['fingerprint'].message_type = _SOURCETESTPLAN_REQUIREMENTS_FINGERPRINT
-_SOURCETESTPLAN_REQUIREMENTS.fields_by_name['parallels'].message_type = _SOURCETESTPLAN_REQUIREMENTS_PARALLELS
-_SOURCETESTPLAN_REQUIREMENTS.fields_by_name['chromeos_config'].message_type = _SOURCETESTPLAN_REQUIREMENTS_CHROMEOSCONFIG
-_SOURCETESTPLAN_REQUIREMENTS.fields_by_name['firmware_ro_versions'].message_type = _SOURCETESTPLAN_REQUIREMENTS_FIRMWAREROVERSIONS
-_SOURCETESTPLAN_REQUIREMENTS.containing_type = _SOURCETESTPLAN
-_SOURCETESTPLAN.fields_by_name['enabled_test_environments'].enum_type = _SOURCETESTPLAN_TESTENVIRONMENT
 _SOURCETESTPLAN.fields_by_name['test_plan_starlark_files'].message_type = _SOURCETESTPLAN_TESTPLANSTARLARKFILE
-_SOURCETESTPLAN.fields_by_name['requirements'].message_type = _SOURCETESTPLAN_REQUIREMENTS
-_SOURCETESTPLAN_TESTENVIRONMENT.containing_type = _SOURCETESTPLAN
 DESCRIPTOR.message_types_by_name['SourceTestPlan'] = _SOURCETESTPLAN
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
@@ -519,98 +128,13 @@
     # @@protoc_insertion_point(class_scope:chromiumos.test.plan.SourceTestPlan.TestPlanStarlarkFile)
     })
   ,
-
-  'Requirements' : _reflection.GeneratedProtocolMessageType('Requirements', (_message.Message,), {
-
-    'KernelVersions' : _reflection.GeneratedProtocolMessageType('KernelVersions', (_message.Message,), {
-      'DESCRIPTOR' : _SOURCETESTPLAN_REQUIREMENTS_KERNELVERSIONS,
-      '__module__' : 'chromiumos.test.plan.source_test_plan_pb2'
-      # @@protoc_insertion_point(class_scope:chromiumos.test.plan.SourceTestPlan.Requirements.KernelVersions)
-      })
-    ,
-
-    'SocFamilies' : _reflection.GeneratedProtocolMessageType('SocFamilies', (_message.Message,), {
-      'DESCRIPTOR' : _SOURCETESTPLAN_REQUIREMENTS_SOCFAMILIES,
-      '__module__' : 'chromiumos.test.plan.source_test_plan_pb2'
-      # @@protoc_insertion_point(class_scope:chromiumos.test.plan.SourceTestPlan.Requirements.SocFamilies)
-      })
-    ,
-
-    'Architectures' : _reflection.GeneratedProtocolMessageType('Architectures', (_message.Message,), {
-      'DESCRIPTOR' : _SOURCETESTPLAN_REQUIREMENTS_ARCHITECTURES,
-      '__module__' : 'chromiumos.test.plan.source_test_plan_pb2'
-      # @@protoc_insertion_point(class_scope:chromiumos.test.plan.SourceTestPlan.Requirements.Architectures)
-      })
-    ,
-
-    'ArcVersions' : _reflection.GeneratedProtocolMessageType('ArcVersions', (_message.Message,), {
-      'DESCRIPTOR' : _SOURCETESTPLAN_REQUIREMENTS_ARCVERSIONS,
-      '__module__' : 'chromiumos.test.plan.source_test_plan_pb2'
-      # @@protoc_insertion_point(class_scope:chromiumos.test.plan.SourceTestPlan.Requirements.ArcVersions)
-      })
-    ,
-
-    'Fingerprint' : _reflection.GeneratedProtocolMessageType('Fingerprint', (_message.Message,), {
-      'DESCRIPTOR' : _SOURCETESTPLAN_REQUIREMENTS_FINGERPRINT,
-      '__module__' : 'chromiumos.test.plan.source_test_plan_pb2'
-      # @@protoc_insertion_point(class_scope:chromiumos.test.plan.SourceTestPlan.Requirements.Fingerprint)
-      })
-    ,
-
-    'Parallels' : _reflection.GeneratedProtocolMessageType('Parallels', (_message.Message,), {
-      'DESCRIPTOR' : _SOURCETESTPLAN_REQUIREMENTS_PARALLELS,
-      '__module__' : 'chromiumos.test.plan.source_test_plan_pb2'
-      # @@protoc_insertion_point(class_scope:chromiumos.test.plan.SourceTestPlan.Requirements.Parallels)
-      })
-    ,
-
-    'ChromeOSConfig' : _reflection.GeneratedProtocolMessageType('ChromeOSConfig', (_message.Message,), {
-      'DESCRIPTOR' : _SOURCETESTPLAN_REQUIREMENTS_CHROMEOSCONFIG,
-      '__module__' : 'chromiumos.test.plan.source_test_plan_pb2'
-      # @@protoc_insertion_point(class_scope:chromiumos.test.plan.SourceTestPlan.Requirements.ChromeOSConfig)
-      })
-    ,
-
-    'FirmwareROVersions' : _reflection.GeneratedProtocolMessageType('FirmwareROVersions', (_message.Message,), {
-
-      'ProgramToMilestoneEntry' : _reflection.GeneratedProtocolMessageType('ProgramToMilestoneEntry', (_message.Message,), {
-        'DESCRIPTOR' : _SOURCETESTPLAN_REQUIREMENTS_FIRMWAREROVERSIONS_PROGRAMTOMILESTONEENTRY,
-        '__module__' : 'chromiumos.test.plan.source_test_plan_pb2'
-        # @@protoc_insertion_point(class_scope:chromiumos.test.plan.SourceTestPlan.Requirements.FirmwareROVersions.ProgramToMilestoneEntry)
-        })
-      ,
-      'DESCRIPTOR' : _SOURCETESTPLAN_REQUIREMENTS_FIRMWAREROVERSIONS,
-      '__module__' : 'chromiumos.test.plan.source_test_plan_pb2'
-      # @@protoc_insertion_point(class_scope:chromiumos.test.plan.SourceTestPlan.Requirements.FirmwareROVersions)
-      })
-    ,
-    'DESCRIPTOR' : _SOURCETESTPLAN_REQUIREMENTS,
-    '__module__' : 'chromiumos.test.plan.source_test_plan_pb2'
-    # @@protoc_insertion_point(class_scope:chromiumos.test.plan.SourceTestPlan.Requirements)
-    })
-  ,
   'DESCRIPTOR' : _SOURCETESTPLAN,
   '__module__' : 'chromiumos.test.plan.source_test_plan_pb2'
   # @@protoc_insertion_point(class_scope:chromiumos.test.plan.SourceTestPlan)
   })
 _sym_db.RegisterMessage(SourceTestPlan)
 _sym_db.RegisterMessage(SourceTestPlan.TestPlanStarlarkFile)
-_sym_db.RegisterMessage(SourceTestPlan.Requirements)
-_sym_db.RegisterMessage(SourceTestPlan.Requirements.KernelVersions)
-_sym_db.RegisterMessage(SourceTestPlan.Requirements.SocFamilies)
-_sym_db.RegisterMessage(SourceTestPlan.Requirements.Architectures)
-_sym_db.RegisterMessage(SourceTestPlan.Requirements.ArcVersions)
-_sym_db.RegisterMessage(SourceTestPlan.Requirements.Fingerprint)
-_sym_db.RegisterMessage(SourceTestPlan.Requirements.Parallels)
-_sym_db.RegisterMessage(SourceTestPlan.Requirements.ChromeOSConfig)
-_sym_db.RegisterMessage(SourceTestPlan.Requirements.FirmwareROVersions)
-_sym_db.RegisterMessage(SourceTestPlan.Requirements.FirmwareROVersions.ProgramToMilestoneEntry)
 
 
 DESCRIPTOR._options = None
-_SOURCETESTPLAN_REQUIREMENTS_FIRMWAREROVERSIONS_PROGRAMTOMILESTONEENTRY._options = None
-_SOURCETESTPLAN.fields_by_name['enabled_test_environments']._options = None
-_SOURCETESTPLAN.fields_by_name['test_tags']._options = None
-_SOURCETESTPLAN.fields_by_name['test_tag_excludes']._options = None
-_SOURCETESTPLAN.fields_by_name['requirements']._options = None
 # @@protoc_insertion_point(module_scope)
diff --git a/api/gen/test_platform/execution/param_pb2.py b/api/gen/test_platform/execution/param_pb2.py
index 2f08f15..4aaf255 100644
--- a/api/gen/test_platform/execution/param_pb2.py
+++ b/api/gen/test_platform/execution/param_pb2.py
@@ -11,6 +11,7 @@
 _sym_db = _symbol_database.Default()
 
 
+from chromite.api.gen.chromiumos.build.api import container_metadata_pb2 as chromiumos_dot_build_dot_api_dot_container__metadata__pb2
 
 
 DESCRIPTOR = _descriptor.FileDescriptor(
@@ -19,8 +20,9 @@
   syntax='proto3',
   serialized_options=b'ZAgo.chromium.org/chromiumos/infra/proto/go/test_platform/execution',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n#test_platform/execution/param.proto\x12\x17test_platform.execution\"\x1f\n\x05Param\x12\x16\n\x0eupload_crashes\x18\x01 \x01(\x08\x42\x43ZAgo.chromium.org/chromiumos/infra/proto/go/test_platform/executionb\x06proto3'
-)
+  serialized_pb=b'\n#test_platform/execution/param.proto\x12\x17test_platform.execution\x1a-chromiumos/build/api/container_metadata.proto\"g\n\x05Param\x12\x16\n\x0eupload_crashes\x18\x01 \x01(\x08\x12\x46\n\x14\x63ontainer_image_info\x18\x08 \x01(\x0b\x32(.chromiumos.build.api.ContainerImageInfoBCZAgo.chromium.org/chromiumos/infra/proto/go/test_platform/executionb\x06proto3'
+  ,
+  dependencies=[chromiumos_dot_build_dot_api_dot_container__metadata__pb2.DESCRIPTOR,])
 
 
 
@@ -40,6 +42,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='container_image_info', full_name='test_platform.execution.Param.container_image_info', index=1,
+      number=8, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -52,10 +61,11 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=64,
-  serialized_end=95,
+  serialized_start=111,
+  serialized_end=214,
 )
 
+_PARAM.fields_by_name['container_image_info'].message_type = chromiumos_dot_build_dot_api_dot_container__metadata__pb2._CONTAINERIMAGEINFO
 DESCRIPTOR.message_types_by_name['Param'] = _PARAM
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
diff --git a/api/gen/test_platform/phosphorus/common_pb2.py b/api/gen/test_platform/phosphorus/common_pb2.py
index 19786d5..c7845c0 100644
--- a/api/gen/test_platform/phosphorus/common_pb2.py
+++ b/api/gen/test_platform/phosphorus/common_pb2.py
@@ -19,7 +19,7 @@
   syntax='proto3',
   serialized_options=b'ZBgo.chromium.org/chromiumos/infra/proto/go/test_platform/phosphorus',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n%test_platform/phosphorus/common.proto\x12\x18test_platform.phosphorus\"&\n\x0e\x42otEnvironment\x12\x14\n\x0c\x61utotest_dir\x18\x01 \x01(\t\"|\n\x0fTaskEnvironment\x12\x13\n\x0bresults_dir\x18\x02 \x01(\t\x12\x18\n\x10test_results_dir\x18\x03 \x01(\t\x12\x1b\n\x13ssp_base_image_name\x18\x04 \x01(\tJ\x04\x08\x01\x10\x02R\x17synchronous_offload_dir\"`\n\nPrejobStep\x12R\n\x18provision_dut_experiment\x18\x01 \x01(\x0b\x32\x30.test_platform.phosphorus.ProvisionDutExperiment\"\xc0\x02\n\x16ProvisionDutExperiment\x12\x0f\n\x07\x65nabled\x18\x01 \x01(\x08\x12g\n\x17\x63ros_version_allow_list\x18\x02 \x01(\x0b\x32\x44.test_platform.phosphorus.ProvisionDutExperiment.CrosVersionSelectorH\x00\x12j\n\x1a\x63ros_version_disallow_list\x18\x03 \x01(\x0b\x32\x44.test_platform.phosphorus.ProvisionDutExperiment.CrosVersionSelectorH\x00\x1a\'\n\x13\x43rosVersionSelector\x12\x10\n\x08prefixes\x18\x01 \x03(\tB\x17\n\x15\x63ros_version_selector\"3\n\x11LogDataUploadStep\x12\x1e\n\x16max_concurrent_uploads\x18\x01 \x01(\x05\"R\n\x10\x46\x65tchCrashesStep\x12\x1f\n\x17\x63rash_server_report_url\x18\x01 \x01(\t\x12\x1d\n\x15\x63rash_server_view_url\x18\x02 \x01(\t\"\xc6\x02\n\x06\x43onfig\x12\x35\n\x03\x62ot\x18\x01 \x01(\x0b\x32(.test_platform.phosphorus.BotEnvironment\x12\x37\n\x04task\x18\x02 \x01(\x0b\x32).test_platform.phosphorus.TaskEnvironment\x12I\n\x14log_data_upload_step\x18\x03 \x01(\x0b\x32+.test_platform.phosphorus.LogDataUploadStep\x12\x46\n\x12\x66\x65tch_crashes_step\x18\x04 \x01(\x0b\x32*.test_platform.phosphorus.FetchCrashesStep\x12\x39\n\x0bprejob_step\x18\x05 \x01(\x0b\x32$.test_platform.phosphorus.PrejobStepBDZBgo.chromium.org/chromiumos/infra/proto/go/test_platform/phosphorusb\x06proto3'
+  serialized_pb=b'\n%test_platform/phosphorus/common.proto\x12\x18test_platform.phosphorus\"&\n\x0e\x42otEnvironment\x12\x14\n\x0c\x61utotest_dir\x18\x01 \x01(\t\"|\n\x0fTaskEnvironment\x12\x13\n\x0bresults_dir\x18\x02 \x01(\t\x12\x18\n\x10test_results_dir\x18\x03 \x01(\t\x12\x1b\n\x13ssp_base_image_name\x18\x04 \x01(\tJ\x04\x08\x01\x10\x02R\x17synchronous_offload_dir\"\xb2\x01\n\nPrejobStep\x12R\n\x18provision_dut_experiment\x18\x01 \x01(\x0b\x32\x30.test_platform.phosphorus.ProvisionDutExperiment\x12P\n\x17\x64ut_topology_experiment\x18\x02 \x01(\x0b\x32/.test_platform.phosphorus.DutTopologyExperiment\"\xc0\x02\n\x16ProvisionDutExperiment\x12\x0f\n\x07\x65nabled\x18\x01 \x01(\x08\x12g\n\x17\x63ros_version_allow_list\x18\x02 \x01(\x0b\x32\x44.test_platform.phosphorus.ProvisionDutExperiment.CrosVersionSelectorH\x00\x12j\n\x1a\x63ros_version_disallow_list\x18\x03 \x01(\x0b\x32\x44.test_platform.phosphorus.ProvisionDutExperiment.CrosVersionSelectorH\x00\x1a\'\n\x13\x43rosVersionSelector\x12\x10\n\x08prefixes\x18\x01 \x03(\tB\x17\n\x15\x63ros_version_selector\"Y\n\x15\x44utTopologyExperiment\x12\x0f\n\x07\x65nabled\x18\x01 \x01(\x08\x12\x16\n\x0etest_allowlist\x18\x02 \x03(\t\x12\x17\n\x0fsuite_allowlist\x18\x03 \x03(\t\"3\n\x11LogDataUploadStep\x12\x1e\n\x16max_concurrent_uploads\x18\x01 \x01(\x05\"R\n\x10\x46\x65tchCrashesStep\x12\x1f\n\x17\x63rash_server_report_url\x18\x01 \x01(\t\x12\x1d\n\x15\x63rash_server_view_url\x18\x02 \x01(\t\"\xc6\x02\n\x06\x43onfig\x12\x35\n\x03\x62ot\x18\x01 \x01(\x0b\x32(.test_platform.phosphorus.BotEnvironment\x12\x37\n\x04task\x18\x02 \x01(\x0b\x32).test_platform.phosphorus.TaskEnvironment\x12I\n\x14log_data_upload_step\x18\x03 \x01(\x0b\x32+.test_platform.phosphorus.LogDataUploadStep\x12\x46\n\x12\x66\x65tch_crashes_step\x18\x04 \x01(\x0b\x32*.test_platform.phosphorus.FetchCrashesStep\x12\x39\n\x0bprejob_step\x18\x05 \x01(\x0b\x32$.test_platform.phosphorus.PrejobStepBDZBgo.chromium.org/chromiumos/infra/proto/go/test_platform/phosphorusb\x06proto3'
 )
 
 
@@ -118,6 +118,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='dut_topology_experiment', full_name='test_platform.phosphorus.PrejobStep.dut_topology_experiment', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -130,8 +137,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=233,
-  serialized_end=329,
+  serialized_start=234,
+  serialized_end=412,
 )
 
 
@@ -162,8 +169,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=588,
-  serialized_end=627,
+  serialized_start=671,
+  serialized_end=710,
 )
 
 _PROVISIONDUTEXPERIMENT = _descriptor.Descriptor(
@@ -212,8 +219,54 @@
       create_key=_descriptor._internal_create_key,
     fields=[]),
   ],
-  serialized_start=332,
-  serialized_end=652,
+  serialized_start=415,
+  serialized_end=735,
+)
+
+
+_DUTTOPOLOGYEXPERIMENT = _descriptor.Descriptor(
+  name='DutTopologyExperiment',
+  full_name='test_platform.phosphorus.DutTopologyExperiment',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='enabled', full_name='test_platform.phosphorus.DutTopologyExperiment.enabled', index=0,
+      number=1, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='test_allowlist', full_name='test_platform.phosphorus.DutTopologyExperiment.test_allowlist', index=1,
+      number=2, type=9, cpp_type=9, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='suite_allowlist', full_name='test_platform.phosphorus.DutTopologyExperiment.suite_allowlist', index=2,
+      number=3, type=9, cpp_type=9, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=737,
+  serialized_end=826,
 )
 
 
@@ -244,8 +297,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=654,
-  serialized_end=705,
+  serialized_start=828,
+  serialized_end=879,
 )
 
 
@@ -283,8 +336,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=707,
-  serialized_end=789,
+  serialized_start=881,
+  serialized_end=963,
 )
 
 
@@ -343,11 +396,12 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=792,
-  serialized_end=1118,
+  serialized_start=966,
+  serialized_end=1292,
 )
 
 _PREJOBSTEP.fields_by_name['provision_dut_experiment'].message_type = _PROVISIONDUTEXPERIMENT
+_PREJOBSTEP.fields_by_name['dut_topology_experiment'].message_type = _DUTTOPOLOGYEXPERIMENT
 _PROVISIONDUTEXPERIMENT_CROSVERSIONSELECTOR.containing_type = _PROVISIONDUTEXPERIMENT
 _PROVISIONDUTEXPERIMENT.fields_by_name['cros_version_allow_list'].message_type = _PROVISIONDUTEXPERIMENT_CROSVERSIONSELECTOR
 _PROVISIONDUTEXPERIMENT.fields_by_name['cros_version_disallow_list'].message_type = _PROVISIONDUTEXPERIMENT_CROSVERSIONSELECTOR
@@ -366,6 +420,7 @@
 DESCRIPTOR.message_types_by_name['TaskEnvironment'] = _TASKENVIRONMENT
 DESCRIPTOR.message_types_by_name['PrejobStep'] = _PREJOBSTEP
 DESCRIPTOR.message_types_by_name['ProvisionDutExperiment'] = _PROVISIONDUTEXPERIMENT
+DESCRIPTOR.message_types_by_name['DutTopologyExperiment'] = _DUTTOPOLOGYEXPERIMENT
 DESCRIPTOR.message_types_by_name['LogDataUploadStep'] = _LOGDATAUPLOADSTEP
 DESCRIPTOR.message_types_by_name['FetchCrashesStep'] = _FETCHCRASHESSTEP
 DESCRIPTOR.message_types_by_name['Config'] = _CONFIG
@@ -407,6 +462,13 @@
 _sym_db.RegisterMessage(ProvisionDutExperiment)
 _sym_db.RegisterMessage(ProvisionDutExperiment.CrosVersionSelector)
 
+DutTopologyExperiment = _reflection.GeneratedProtocolMessageType('DutTopologyExperiment', (_message.Message,), {
+  'DESCRIPTOR' : _DUTTOPOLOGYEXPERIMENT,
+  '__module__' : 'test_platform.phosphorus.common_pb2'
+  # @@protoc_insertion_point(class_scope:test_platform.phosphorus.DutTopologyExperiment)
+  })
+_sym_db.RegisterMessage(DutTopologyExperiment)
+
 LogDataUploadStep = _reflection.GeneratedProtocolMessageType('LogDataUploadStep', (_message.Message,), {
   'DESCRIPTOR' : _LOGDATAUPLOADSTEP,
   '__module__' : 'test_platform.phosphorus.common_pb2'
diff --git a/api/gen/test_platform/phosphorus/runtest_pb2.py b/api/gen/test_platform/phosphorus/runtest_pb2.py
index c5d79ac..3d96e96 100644
--- a/api/gen/test_platform/phosphorus/runtest_pb2.py
+++ b/api/gen/test_platform/phosphorus/runtest_pb2.py
@@ -11,6 +11,7 @@
 _sym_db = _symbol_database.Default()
 
 
+from chromite.api.gen.chromiumos.build.api import container_metadata_pb2 as chromiumos_dot_build_dot_api_dot_container__metadata__pb2
 from chromite.third_party.google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
 from chromite.api.gen.test_platform.phosphorus import common_pb2 as test__platform_dot_phosphorus_dot_common__pb2
 
@@ -21,9 +22,9 @@
   syntax='proto3',
   serialized_options=b'ZBgo.chromium.org/chromiumos/infra/proto/go/test_platform/phosphorus',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n&test_platform/phosphorus/runtest.proto\x12\x18test_platform.phosphorus\x1a\x1fgoogle/protobuf/timestamp.proto\x1a%test_platform/phosphorus/common.proto\"\xf7\x03\n\x0eRunTestRequest\x12\x30\n\x06\x63onfig\x18\x01 \x01(\x0b\x32 .test_platform.phosphorus.Config\x12\x15\n\rdut_hostnames\x18\x02 \x03(\t\x12\x45\n\x08\x61utotest\x18\x03 \x01(\x0b\x32\x31.test_platform.phosphorus.RunTestRequest.AutotestH\x00\x12,\n\x08\x64\x65\x61\x64line\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x1a\x8b\x02\n\x08\x41utotest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x11\n\ttest_args\x18\x02 \x01(\t\x12\x14\n\x0c\x64isplay_name\x18\x03 \x01(\t\x12\x16\n\x0eis_client_test\x18\x04 \x01(\x08\x12O\n\x07keyvals\x18\x05 \x03(\x0b\x32>.test_platform.phosphorus.RunTestRequest.Autotest.KeyvalsEntry\x12\x11\n\tpeer_duts\x18\x06 \x03(\t\x12\x1c\n\x14image_storage_server\x18\x07 \x01(\t\x1a.\n\x0cKeyvalsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\x06\n\x04testJ\x04\x08\x04\x10\x05R\x0b\x65nvironment\"\xbd\x01\n\x0fRunTestResponse\x12>\n\x05state\x18\x01 \x01(\x0e\x32/.test_platform.phosphorus.RunTestResponse.State\x12\x13\n\x0bresults_dir\x18\x02 \x01(\t\"U\n\x05State\x12\x15\n\x11STATE_UNSPECIFIED\x10\x00\x12\r\n\tSUCCEEDED\x10\x01\x12\n\n\x06\x46\x41ILED\x10\x02\x12\r\n\tTIMED_OUT\x10\x03\x12\x0b\n\x07\x41\x42ORTED\x10\x04\x42\x44ZBgo.chromium.org/chromiumos/infra/proto/go/test_platform/phosphorusb\x06proto3'
+  serialized_pb=b'\n&test_platform/phosphorus/runtest.proto\x12\x18test_platform.phosphorus\x1a-chromiumos/build/api/container_metadata.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a%test_platform/phosphorus/common.proto\"\xbf\x04\n\x0eRunTestRequest\x12\x30\n\x06\x63onfig\x18\x01 \x01(\x0b\x32 .test_platform.phosphorus.Config\x12\x15\n\rdut_hostnames\x18\x02 \x03(\t\x12\x45\n\x08\x61utotest\x18\x03 \x01(\x0b\x32\x31.test_platform.phosphorus.RunTestRequest.AutotestH\x00\x12,\n\x08\x64\x65\x61\x64line\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x46\n\x14\x63ontainer_image_info\x18\x06 \x01(\x0b\x32(.chromiumos.build.api.ContainerImageInfo\x1a\x8b\x02\n\x08\x41utotest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x11\n\ttest_args\x18\x02 \x01(\t\x12\x14\n\x0c\x64isplay_name\x18\x03 \x01(\t\x12\x16\n\x0eis_client_test\x18\x04 \x01(\x08\x12O\n\x07keyvals\x18\x05 \x03(\x0b\x32>.test_platform.phosphorus.RunTestRequest.Autotest.KeyvalsEntry\x12\x11\n\tpeer_duts\x18\x06 \x03(\t\x12\x1c\n\x14image_storage_server\x18\x07 \x01(\t\x1a.\n\x0cKeyvalsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\x06\n\x04testJ\x04\x08\x04\x10\x05R\x0b\x65nvironment\"\xbd\x01\n\x0fRunTestResponse\x12>\n\x05state\x18\x01 \x01(\x0e\x32/.test_platform.phosphorus.RunTestResponse.State\x12\x13\n\x0bresults_dir\x18\x02 \x01(\t\"U\n\x05State\x12\x15\n\x11STATE_UNSPECIFIED\x10\x00\x12\r\n\tSUCCEEDED\x10\x01\x12\n\n\x06\x46\x41ILED\x10\x02\x12\r\n\tTIMED_OUT\x10\x03\x12\x0b\n\x07\x41\x42ORTED\x10\x04\x42\x44ZBgo.chromium.org/chromiumos/infra/proto/go/test_platform/phosphorusb\x06proto3'
   ,
-  dependencies=[google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,test__platform_dot_phosphorus_dot_common__pb2.DESCRIPTOR,])
+  dependencies=[chromiumos_dot_build_dot_api_dot_container__metadata__pb2.DESCRIPTOR,google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,test__platform_dot_phosphorus_dot_common__pb2.DESCRIPTOR,])
 
 
 
@@ -62,8 +63,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=751,
-  serialized_end=836,
+  serialized_start=870,
+  serialized_end=955,
 )
 _sym_db.RegisterEnumDescriptor(_RUNTESTRESPONSE_STATE)
 
@@ -102,8 +103,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=571,
-  serialized_end=617,
+  serialized_start=690,
+  serialized_end=736,
 )
 
 _RUNTESTREQUEST_AUTOTEST = _descriptor.Descriptor(
@@ -175,8 +176,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=350,
-  serialized_end=617,
+  serialized_start=469,
+  serialized_end=736,
 )
 
 _RUNTESTREQUEST = _descriptor.Descriptor(
@@ -215,6 +216,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='container_image_info', full_name='test_platform.phosphorus.RunTestRequest.container_image_info', index=4,
+      number=6, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -232,8 +240,8 @@
       create_key=_descriptor._internal_create_key,
     fields=[]),
   ],
-  serialized_start=141,
-  serialized_end=644,
+  serialized_start=188,
+  serialized_end=763,
 )
 
 
@@ -272,8 +280,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=647,
-  serialized_end=836,
+  serialized_start=766,
+  serialized_end=955,
 )
 
 _RUNTESTREQUEST_AUTOTEST_KEYVALSENTRY.containing_type = _RUNTESTREQUEST_AUTOTEST
@@ -282,6 +290,7 @@
 _RUNTESTREQUEST.fields_by_name['config'].message_type = test__platform_dot_phosphorus_dot_common__pb2._CONFIG
 _RUNTESTREQUEST.fields_by_name['autotest'].message_type = _RUNTESTREQUEST_AUTOTEST
 _RUNTESTREQUEST.fields_by_name['deadline'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP
+_RUNTESTREQUEST.fields_by_name['container_image_info'].message_type = chromiumos_dot_build_dot_api_dot_container__metadata__pb2._CONTAINERIMAGEINFO
 _RUNTESTREQUEST.oneofs_by_name['test'].fields.append(
   _RUNTESTREQUEST.fields_by_name['autotest'])
 _RUNTESTREQUEST.fields_by_name['autotest'].containing_oneof = _RUNTESTREQUEST.oneofs_by_name['test']
diff --git a/api/gen/test_platform/request_pb2.py b/api/gen/test_platform/request_pb2.py
index 262bf29..a6f4a82 100644
--- a/api/gen/test_platform/request_pb2.py
+++ b/api/gen/test_platform/request_pb2.py
@@ -23,7 +23,7 @@
   syntax='proto3',
   serialized_options=b'Z7go.chromium.org/chromiumos/infra/proto/go/test_platform',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n\x1btest_platform/request.proto\x12\rtest_platform\x1a chromite/api/test_metadata.proto\x1a\x17\x63hromiumos/common.proto\x1a\x1egoogle/protobuf/duration.proto\x1a#test_platform/execution/param.proto\"\xa3\x19\n\x07Request\x12-\n\x06params\x18\x01 \x01(\x0b\x32\x1d.test_platform.Request.Params\x12\x32\n\ttest_plan\x18\x05 \x01(\x0b\x32\x1f.test_platform.Request.TestPlan\x1a\xfb\x12\n\x06Params\x12M\n\x13hardware_attributes\x18\x01 \x01(\x0b\x32\x30.test_platform.Request.Params.HardwareAttributes\x12M\n\x13software_attributes\x18\x02 \x01(\x0b\x32\x30.test_platform.Request.Params.SoftwareAttributes\x12M\n\x13\x66reeform_attributes\x18\t \x01(\x0b\x32\x30.test_platform.Request.Params.FreeformAttributes\x12O\n\x15software_dependencies\x18\x03 \x03(\x0b\x32\x30.test_platform.Request.Params.SoftwareDependency\x12H\n\x11secondary_devices\x18\x0e \x03(\x0b\x32-.test_platform.Request.Params.SecondaryDevice\x12<\n\nscheduling\x18\x04 \x01(\x0b\x32(.test_platform.Request.Params.Scheduling\x12\x32\n\x05retry\x18\x05 \x01(\x0b\x32#.test_platform.Request.Params.Retry\x12\x38\n\x08metadata\x18\x06 \x01(\x0b\x32&.test_platform.Request.Params.Metadata\x12\x30\n\x04time\x18\x07 \x01(\x0b\x32\".test_platform.Request.Params.Time\x12>\n\x0b\x64\x65\x63orations\x18\x08 \x01(\x0b\x32).test_platform.Request.Params.Decorations\x12<\n\nmigrations\x18\x0c \x01(\x0b\x32(.test_platform.Request.Params.Migrations\x12\x37\n\x0f\x65xecution_param\x18\r \x01(\x0b\x32\x1e.test_platform.execution.Param\x1a#\n\x12HardwareAttributes\x12\r\n\x05model\x18\x01 \x01(\t\x1a\x43\n\x12SoftwareAttributes\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x1a\x31\n\x12\x46reeformAttributes\x12\x1b\n\x13swarming_dimensions\x18\x01 \x03(\t\x1a\xaf\x01\n\x12SoftwareDependency\x12\x18\n\x0e\x63hromeos_build\x18\x03 \x01(\tH\x00\x12#\n\x19\x63hromeos_build_gcs_bucket\x18\x07 \x01(\tH\x00\x12\x1b\n\x11ro_firmware_build\x18\x04 \x01(\tH\x00\x12\x1b\n\x11rw_firmware_build\x18\x05 \x01(\tH\x00\x12\x19\n\x0flacros_gcs_path\x18\x06 \x01(\tH\x00\x42\x05\n\x03\x64\x65p\x1a\x80\x02\n\x0fSecondaryDevice\x12M\n\x13software_attributes\x18\x01 \x01(\x0b\x32\x30.test_platform.Request.Params.SoftwareAttributes\x12M\n\x13hardware_attributes\x18\x02 \x01(\x0b\x32\x30.test_platform.Request.Params.HardwareAttributes\x12O\n\x15software_dependencies\x18\x03 \x03(\x0b\x32\x30.test_platform.Request.Params.SoftwareDependency\x1a\x9e\x03\n\nScheduling\x12L\n\x0cmanaged_pool\x18\x01 \x01(\x0e\x32\x34.test_platform.Request.Params.Scheduling.ManagedPoolH\x00\x12\x18\n\x0eunmanaged_pool\x18\x02 \x01(\tH\x00\x12\x10\n\x08priority\x18\x04 \x01(\x03\x12\x12\n\nqs_account\x18\x05 \x01(\t\"\xf9\x01\n\x0bManagedPool\x12\x1c\n\x18MANAGED_POOL_UNSPECIFIED\x10\x00\x12\x13\n\x0fMANAGED_POOL_CQ\x10\x01\x12\x14\n\x10MANAGED_POOL_BVT\x10\x02\x12\x17\n\x13MANAGED_POOL_SUITES\x10\x03\x12\x14\n\x10MANAGED_POOL_CTS\x10\x04\x12\x1d\n\x19MANAGED_POOL_CTS_PERBUILD\x10\x05\x12\x1b\n\x17MANAGED_POOL_CONTINUOUS\x10\x06\x12\x1e\n\x1aMANAGED_POOL_ARC_PRESUBMIT\x10\x07\x12\x16\n\x12MANAGED_POOL_QUOTA\x10\x08\x42\x06\n\x04pool\x1a#\n\x05Retry\x12\r\n\x05\x61llow\x18\x01 \x01(\x08\x12\x0b\n\x03max\x18\x02 \x01(\x05\x1aH\n\x08Metadata\x12\x19\n\x11test_metadata_url\x18\x01 \x01(\t\x12!\n\x19\x64\x65\x62ug_symbols_archive_url\x18\x02 \x01(\t\x1a;\n\x04Time\x12\x33\n\x10maximum_duration\x18\x01 \x01(\x0b\x32\x19.google.protobuf.Duration\x1a\xaa\x02\n\x0b\x44\x65\x63orations\x12X\n\x10\x61utotest_keyvals\x18\x01 \x03(\x0b\x32>.test_platform.Request.Params.Decorations.AutotestKeyvalsEntry\x12\x0c\n\x04tags\x18\x02 \x03(\t\x12J\n\ttest_args\x18\x03 \x03(\x0b\x32\x37.test_platform.Request.Params.Decorations.TestArgsEntry\x1a\x36\n\x14\x41utotestKeyvalsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a/\n\rTestArgsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\x65\n\nMigrationsJ\x04\x08\x01\x10\x02J\x04\x08\x02\x10\x03J\x04\x08\x03\x10\x04R\x0fuse_test_runnerR\x1a\x65nable_synchronous_offloadR\x18notificationless_offloadJ\x04\x08\x0b\x10\x0cJ\x04\x08\n\x10\x0bR\rnotificationsR\x06legacy\x1a\x15\n\x05Suite\x12\x0c\n\x04name\x18\x01 \x01(\t\x1a\x8e\x01\n\x04Test\x12\x38\n\x08\x61utotest\x18\x01 \x01(\x0b\x32$.test_platform.Request.Test.AutotestH\x00\x1a\x41\n\x08\x41utotest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x11\n\ttest_args\x18\x02 \x01(\t\x12\x14\n\x0c\x64isplay_name\x18\x03 \x01(\tB\t\n\x07harness\x1a\xe4\x02\n\x0b\x45numeration\x12S\n\x14\x61utotest_invocations\x18\x02 \x03(\x0b\x32\x35.test_platform.Request.Enumeration.AutotestInvocation\x1a\xff\x01\n\x12\x41utotestInvocation\x12(\n\x04test\x18\x01 \x01(\x0b\x32\x1a.chromite.api.AutotestTest\x12\x11\n\ttest_args\x18\x02 \x01(\t\x12\x14\n\x0c\x64isplay_name\x18\x03 \x01(\t\x12`\n\x0eresult_keyvals\x18\x04 \x03(\x0b\x32H.test_platform.Request.Enumeration.AutotestInvocation.ResultKeyvalsEntry\x1a\x34\n\x12ResultKeyvalsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\x9b\x01\n\x08TestPlan\x12+\n\x05suite\x18\x01 \x03(\x0b\x32\x1c.test_platform.Request.Suite\x12)\n\x04test\x18\x02 \x03(\x0b\x32\x1b.test_platform.Request.Test\x12\x37\n\x0b\x65numeration\x18\x03 \x01(\x0b\x32\".test_platform.Request.EnumerationJ\x04\x08\x06\x10\x07J\x04\x08\x07\x10\x08\x42\x39Z7go.chromium.org/chromiumos/infra/proto/go/test_platformb\x06proto3'
+  serialized_pb=b'\n\x1btest_platform/request.proto\x12\rtest_platform\x1a chromite/api/test_metadata.proto\x1a\x17\x63hromiumos/common.proto\x1a\x1egoogle/protobuf/duration.proto\x1a#test_platform/execution/param.proto\"\xeb\x1a\n\x07Request\x12-\n\x06params\x18\x01 \x01(\x0b\x32\x1d.test_platform.Request.Params\x12\x32\n\ttest_plan\x18\x05 \x01(\x0b\x32\x1f.test_platform.Request.TestPlan\x1a\xc3\x14\n\x06Params\x12M\n\x13hardware_attributes\x18\x01 \x01(\x0b\x32\x30.test_platform.Request.Params.HardwareAttributes\x12M\n\x13software_attributes\x18\x02 \x01(\x0b\x32\x30.test_platform.Request.Params.SoftwareAttributes\x12M\n\x13\x66reeform_attributes\x18\t \x01(\x0b\x32\x30.test_platform.Request.Params.FreeformAttributes\x12O\n\x15software_dependencies\x18\x03 \x03(\x0b\x32\x30.test_platform.Request.Params.SoftwareDependency\x12H\n\x11secondary_devices\x18\x0e \x03(\x0b\x32-.test_platform.Request.Params.SecondaryDevice\x12<\n\nscheduling\x18\x04 \x01(\x0b\x32(.test_platform.Request.Params.Scheduling\x12\x32\n\x05retry\x18\x05 \x01(\x0b\x32#.test_platform.Request.Params.Retry\x12\x38\n\x08metadata\x18\x06 \x01(\x0b\x32&.test_platform.Request.Params.Metadata\x12\x30\n\x04time\x18\x07 \x01(\x0b\x32\".test_platform.Request.Params.Time\x12>\n\x0b\x64\x65\x63orations\x18\x08 \x01(\x0b\x32).test_platform.Request.Params.Decorations\x12<\n\nmigrations\x18\x0c \x01(\x0b\x32(.test_platform.Request.Params.Migrations\x12\x37\n\x0f\x65xecution_param\x18\r \x01(\x0b\x32\x1e.test_platform.execution.Param\x12T\n\x17test_execution_behavior\x18\x0f \x01(\x0e\x32\x33.test_platform.Request.Params.TestExecutionBehavior\x1a\x42\n\x12HardwareAttributes\x12\r\n\x05model\x18\x01 \x01(\t\x12\x1d\n\x15require_stable_device\x18\x02 \x01(\x08\x1a\x43\n\x12SoftwareAttributes\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x1a\x31\n\x12\x46reeformAttributes\x12\x1b\n\x13swarming_dimensions\x18\x01 \x03(\t\x1a\xaf\x01\n\x12SoftwareDependency\x12\x18\n\x0e\x63hromeos_build\x18\x03 \x01(\tH\x00\x12#\n\x19\x63hromeos_build_gcs_bucket\x18\x07 \x01(\tH\x00\x12\x1b\n\x11ro_firmware_build\x18\x04 \x01(\tH\x00\x12\x1b\n\x11rw_firmware_build\x18\x05 \x01(\tH\x00\x12\x19\n\x0flacros_gcs_path\x18\x06 \x01(\tH\x00\x42\x05\n\x03\x64\x65p\x1a\x80\x02\n\x0fSecondaryDevice\x12M\n\x13software_attributes\x18\x01 \x01(\x0b\x32\x30.test_platform.Request.Params.SoftwareAttributes\x12M\n\x13hardware_attributes\x18\x02 \x01(\x0b\x32\x30.test_platform.Request.Params.HardwareAttributes\x12O\n\x15software_dependencies\x18\x03 \x03(\x0b\x32\x30.test_platform.Request.Params.SoftwareDependency\x1a\x9e\x03\n\nScheduling\x12L\n\x0cmanaged_pool\x18\x01 \x01(\x0e\x32\x34.test_platform.Request.Params.Scheduling.ManagedPoolH\x00\x12\x18\n\x0eunmanaged_pool\x18\x02 \x01(\tH\x00\x12\x10\n\x08priority\x18\x04 \x01(\x03\x12\x12\n\nqs_account\x18\x05 \x01(\t\"\xf9\x01\n\x0bManagedPool\x12\x1c\n\x18MANAGED_POOL_UNSPECIFIED\x10\x00\x12\x13\n\x0fMANAGED_POOL_CQ\x10\x01\x12\x14\n\x10MANAGED_POOL_BVT\x10\x02\x12\x17\n\x13MANAGED_POOL_SUITES\x10\x03\x12\x14\n\x10MANAGED_POOL_CTS\x10\x04\x12\x1d\n\x19MANAGED_POOL_CTS_PERBUILD\x10\x05\x12\x1b\n\x17MANAGED_POOL_CONTINUOUS\x10\x06\x12\x1e\n\x1aMANAGED_POOL_ARC_PRESUBMIT\x10\x07\x12\x16\n\x12MANAGED_POOL_QUOTA\x10\x08\x42\x06\n\x04pool\x1a#\n\x05Retry\x12\r\n\x05\x61llow\x18\x01 \x01(\x08\x12\x0b\n\x03max\x18\x02 \x01(\x05\x1aH\n\x08Metadata\x12\x19\n\x11test_metadata_url\x18\x01 \x01(\t\x12!\n\x19\x64\x65\x62ug_symbols_archive_url\x18\x02 \x01(\t\x1a;\n\x04Time\x12\x33\n\x10maximum_duration\x18\x01 \x01(\x0b\x32\x19.google.protobuf.Duration\x1a\xaa\x02\n\x0b\x44\x65\x63orations\x12X\n\x10\x61utotest_keyvals\x18\x01 \x03(\x0b\x32>.test_platform.Request.Params.Decorations.AutotestKeyvalsEntry\x12\x0c\n\x04tags\x18\x02 \x03(\t\x12J\n\ttest_args\x18\x03 \x03(\x0b\x32\x37.test_platform.Request.Params.Decorations.TestArgsEntry\x1a\x36\n\x14\x41utotestKeyvalsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a/\n\rTestArgsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\x65\n\nMigrationsJ\x04\x08\x01\x10\x02J\x04\x08\x02\x10\x03J\x04\x08\x03\x10\x04R\x0fuse_test_runnerR\x1a\x65nable_synchronous_offloadR\x18notificationless_offload\"Q\n\x15TestExecutionBehavior\x12\x18\n\x14\x42\x45HAVIOR_UNSPECIFIED\x10\x00\x12\x0c\n\x08\x43RITICAL\x10\x01\x12\x10\n\x0cNON_CRITICAL\x10\x02J\x04\x08\x0b\x10\x0cJ\x04\x08\n\x10\x0bR\rnotificationsR\x06legacy\x1a\x15\n\x05Suite\x12\x0c\n\x04name\x18\x01 \x01(\t\x1a\x8e\x01\n\x04Test\x12\x38\n\x08\x61utotest\x18\x01 \x01(\x0b\x32$.test_platform.Request.Test.AutotestH\x00\x1a\x41\n\x08\x41utotest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x11\n\ttest_args\x18\x02 \x01(\t\x12\x14\n\x0c\x64isplay_name\x18\x03 \x01(\tB\t\n\x07harness\x1a\xe4\x02\n\x0b\x45numeration\x12S\n\x14\x61utotest_invocations\x18\x02 \x03(\x0b\x32\x35.test_platform.Request.Enumeration.AutotestInvocation\x1a\xff\x01\n\x12\x41utotestInvocation\x12(\n\x04test\x18\x01 \x01(\x0b\x32\x1a.chromite.api.AutotestTest\x12\x11\n\ttest_args\x18\x02 \x01(\t\x12\x14\n\x0c\x64isplay_name\x18\x03 \x01(\t\x12`\n\x0eresult_keyvals\x18\x04 \x03(\x0b\x32H.test_platform.Request.Enumeration.AutotestInvocation.ResultKeyvalsEntry\x1a\x34\n\x12ResultKeyvalsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\x9b\x01\n\x08TestPlan\x12+\n\x05suite\x18\x01 \x03(\x0b\x32\x1c.test_platform.Request.Suite\x12)\n\x04test\x18\x02 \x03(\x0b\x32\x1b.test_platform.Request.Test\x12\x37\n\x0b\x65numeration\x18\x03 \x01(\x0b\x32\".test_platform.Request.EnumerationJ\x04\x08\x06\x10\x07J\x04\x08\x07\x10\x08\x42\x39Z7go.chromium.org/chromiumos/infra/proto/go/test_platformb\x06proto3'
   ,
   dependencies=[chromite_dot_api_dot_test__metadata__pb2.DESCRIPTOR,chromiumos_dot_common__pb2.DESCRIPTOR,google_dot_protobuf_dot_duration__pb2.DESCRIPTOR,test__platform_dot_execution_dot_param__pb2.DESCRIPTOR,])
 
@@ -84,11 +84,41 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1845,
-  serialized_end=2094,
+  serialized_start=1962,
+  serialized_end=2211,
 )
 _sym_db.RegisterEnumDescriptor(_REQUEST_PARAMS_SCHEDULING_MANAGEDPOOL)
 
+_REQUEST_PARAMS_TESTEXECUTIONBEHAVIOR = _descriptor.EnumDescriptor(
+  name='TestExecutionBehavior',
+  full_name='test_platform.Request.Params.TestExecutionBehavior',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='BEHAVIOR_UNSPECIFIED', index=0, number=0,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='CRITICAL', index=1, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='NON_CRITICAL', index=2, number=2,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=2797,
+  serialized_end=2878,
+)
+_sym_db.RegisterEnumDescriptor(_REQUEST_PARAMS_TESTEXECUTIONBEHAVIOR)
+
 
 _REQUEST_PARAMS_HARDWAREATTRIBUTES = _descriptor.Descriptor(
   name='HardwareAttributes',
@@ -105,6 +135,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='require_stable_device', full_name='test_platform.Request.Params.HardwareAttributes.require_stable_device', index=1,
+      number=2, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -117,8 +154,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1093,
-  serialized_end=1128,
+  serialized_start=1179,
+  serialized_end=1245,
 )
 
 _REQUEST_PARAMS_SOFTWAREATTRIBUTES = _descriptor.Descriptor(
@@ -148,8 +185,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1130,
-  serialized_end=1197,
+  serialized_start=1247,
+  serialized_end=1314,
 )
 
 _REQUEST_PARAMS_FREEFORMATTRIBUTES = _descriptor.Descriptor(
@@ -179,8 +216,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1199,
-  serialized_end=1248,
+  serialized_start=1316,
+  serialized_end=1365,
 )
 
 _REQUEST_PARAMS_SOFTWAREDEPENDENCY = _descriptor.Descriptor(
@@ -243,8 +280,8 @@
       create_key=_descriptor._internal_create_key,
     fields=[]),
   ],
-  serialized_start=1251,
-  serialized_end=1426,
+  serialized_start=1368,
+  serialized_end=1543,
 )
 
 _REQUEST_PARAMS_SECONDARYDEVICE = _descriptor.Descriptor(
@@ -288,8 +325,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1429,
-  serialized_end=1685,
+  serialized_start=1546,
+  serialized_end=1802,
 )
 
 _REQUEST_PARAMS_SCHEDULING = _descriptor.Descriptor(
@@ -346,8 +383,8 @@
       create_key=_descriptor._internal_create_key,
     fields=[]),
   ],
-  serialized_start=1688,
-  serialized_end=2102,
+  serialized_start=1805,
+  serialized_end=2219,
 )
 
 _REQUEST_PARAMS_RETRY = _descriptor.Descriptor(
@@ -384,8 +421,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2104,
-  serialized_end=2139,
+  serialized_start=2221,
+  serialized_end=2256,
 )
 
 _REQUEST_PARAMS_METADATA = _descriptor.Descriptor(
@@ -422,8 +459,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2141,
-  serialized_end=2213,
+  serialized_start=2258,
+  serialized_end=2330,
 )
 
 _REQUEST_PARAMS_TIME = _descriptor.Descriptor(
@@ -453,8 +490,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2215,
-  serialized_end=2274,
+  serialized_start=2332,
+  serialized_end=2391,
 )
 
 _REQUEST_PARAMS_DECORATIONS_AUTOTESTKEYVALSENTRY = _descriptor.Descriptor(
@@ -491,8 +528,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2472,
-  serialized_end=2526,
+  serialized_start=2589,
+  serialized_end=2643,
 )
 
 _REQUEST_PARAMS_DECORATIONS_TESTARGSENTRY = _descriptor.Descriptor(
@@ -529,8 +566,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2528,
-  serialized_end=2575,
+  serialized_start=2645,
+  serialized_end=2692,
 )
 
 _REQUEST_PARAMS_DECORATIONS = _descriptor.Descriptor(
@@ -574,8 +611,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2277,
-  serialized_end=2575,
+  serialized_start=2394,
+  serialized_end=2692,
 )
 
 _REQUEST_PARAMS_MIGRATIONS = _descriptor.Descriptor(
@@ -598,8 +635,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2577,
-  serialized_end=2678,
+  serialized_start=2694,
+  serialized_end=2795,
 )
 
 _REQUEST_PARAMS = _descriptor.Descriptor(
@@ -694,11 +731,19 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='test_execution_behavior', full_name='test_platform.Request.Params.test_execution_behavior', index=12,
+      number=15, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
   nested_types=[_REQUEST_PARAMS_HARDWAREATTRIBUTES, _REQUEST_PARAMS_SOFTWAREATTRIBUTES, _REQUEST_PARAMS_FREEFORMATTRIBUTES, _REQUEST_PARAMS_SOFTWAREDEPENDENCY, _REQUEST_PARAMS_SECONDARYDEVICE, _REQUEST_PARAMS_SCHEDULING, _REQUEST_PARAMS_RETRY, _REQUEST_PARAMS_METADATA, _REQUEST_PARAMS_TIME, _REQUEST_PARAMS_DECORATIONS, _REQUEST_PARAMS_MIGRATIONS, ],
   enum_types=[
+    _REQUEST_PARAMS_TESTEXECUTIONBEHAVIOR,
   ],
   serialized_options=None,
   is_extendable=False,
@@ -707,7 +752,7 @@
   oneofs=[
   ],
   serialized_start=286,
-  serialized_end=2713,
+  serialized_end=2913,
 )
 
 _REQUEST_SUITE = _descriptor.Descriptor(
@@ -737,8 +782,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2715,
-  serialized_end=2736,
+  serialized_start=2915,
+  serialized_end=2936,
 )
 
 _REQUEST_TEST_AUTOTEST = _descriptor.Descriptor(
@@ -782,8 +827,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2805,
-  serialized_end=2870,
+  serialized_start=3005,
+  serialized_end=3070,
 )
 
 _REQUEST_TEST = _descriptor.Descriptor(
@@ -818,8 +863,8 @@
       create_key=_descriptor._internal_create_key,
     fields=[]),
   ],
-  serialized_start=2739,
-  serialized_end=2881,
+  serialized_start=2939,
+  serialized_end=3081,
 )
 
 _REQUEST_ENUMERATION_AUTOTESTINVOCATION_RESULTKEYVALSENTRY = _descriptor.Descriptor(
@@ -856,8 +901,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3188,
-  serialized_end=3240,
+  serialized_start=3388,
+  serialized_end=3440,
 )
 
 _REQUEST_ENUMERATION_AUTOTESTINVOCATION = _descriptor.Descriptor(
@@ -908,8 +953,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2985,
-  serialized_end=3240,
+  serialized_start=3185,
+  serialized_end=3440,
 )
 
 _REQUEST_ENUMERATION = _descriptor.Descriptor(
@@ -939,8 +984,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2884,
-  serialized_end=3240,
+  serialized_start=3084,
+  serialized_end=3440,
 )
 
 _REQUEST_TESTPLAN = _descriptor.Descriptor(
@@ -984,8 +1029,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3243,
-  serialized_end=3398,
+  serialized_start=3443,
+  serialized_end=3598,
 )
 
 _REQUEST = _descriptor.Descriptor(
@@ -1023,7 +1068,7 @@
   oneofs=[
   ],
   serialized_start=175,
-  serialized_end=3410,
+  serialized_end=3610,
 )
 
 _REQUEST_PARAMS_HARDWAREATTRIBUTES.containing_type = _REQUEST_PARAMS
@@ -1081,7 +1126,9 @@
 _REQUEST_PARAMS.fields_by_name['decorations'].message_type = _REQUEST_PARAMS_DECORATIONS
 _REQUEST_PARAMS.fields_by_name['migrations'].message_type = _REQUEST_PARAMS_MIGRATIONS
 _REQUEST_PARAMS.fields_by_name['execution_param'].message_type = test__platform_dot_execution_dot_param__pb2._PARAM
+_REQUEST_PARAMS.fields_by_name['test_execution_behavior'].enum_type = _REQUEST_PARAMS_TESTEXECUTIONBEHAVIOR
 _REQUEST_PARAMS.containing_type = _REQUEST
+_REQUEST_PARAMS_TESTEXECUTIONBEHAVIOR.containing_type = _REQUEST_PARAMS
 _REQUEST_SUITE.containing_type = _REQUEST
 _REQUEST_TEST_AUTOTEST.containing_type = _REQUEST_TEST
 _REQUEST_TEST.fields_by_name['autotest'].message_type = _REQUEST_TEST_AUTOTEST
diff --git a/api/gen/test_platform/skylab_test_runner/request_pb2.py b/api/gen/test_platform/skylab_test_runner/request_pb2.py
index af144ff..592ee23 100644
--- a/api/gen/test_platform/skylab_test_runner/request_pb2.py
+++ b/api/gen/test_platform/skylab_test_runner/request_pb2.py
@@ -11,6 +11,7 @@
 _sym_db = _symbol_database.Default()
 
 
+from chromite.api.gen.chromiumos.build.api import container_metadata_pb2 as chromiumos_dot_build_dot_api_dot_container__metadata__pb2
 from chromite.third_party.google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
 from chromite.api.gen.test_platform.execution import param_pb2 as test__platform_dot_execution_dot_param__pb2
 from chromite.api.gen.test_platform import request_pb2 as test__platform_dot_request__pb2
@@ -22,9 +23,9 @@
   syntax='proto3',
   serialized_options=b'ZJgo.chromium.org/chromiumos/infra/proto/go/test_platform/skylab_test_runner',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n.test_platform/skylab_test_runner/request.proto\x12 test_platform.skylab_test_runner\x1a\x1fgoogle/protobuf/timestamp.proto\x1a#test_platform/execution/param.proto\x1a\x1btest_platform/request.proto\"\x8b\x0b\n\x07Request\x12@\n\x06prejob\x18\x01 \x01(\x0b\x32\x30.test_platform.skylab_test_runner.Request.Prejob\x12<\n\x04test\x18\x02 \x01(\x0b\x32..test_platform.skylab_test_runner.Request.Test\x12,\n\x08\x64\x65\x61\x64line\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x1a\n\x12parent_request_uid\x18\x04 \x01(\t\x12\x17\n\x0fparent_build_id\x18\x05 \x01(\x03\x12\x43\n\x05tests\x18\x06 \x03(\x0b\x32\x34.test_platform.skylab_test_runner.Request.TestsEntry\x12\x37\n\x0f\x65xecution_param\x18\x07 \x01(\x0b\x32\x1e.test_platform.execution.Param\x1a\xfb\x03\n\x06Prejob\x12O\n\x15software_dependencies\x18\x01 \x03(\x0b\x32\x30.test_platform.Request.Params.SoftwareDependency\x12k\n\x14provisionable_labels\x18\x02 \x03(\x0b\x32I.test_platform.skylab_test_runner.Request.Prejob.ProvisionableLabelsEntryB\x02\x18\x01\x12\x0f\n\x07use_tls\x18\x03 \x01(\x08\x12M\n\x13software_attributes\x18\x04 \x01(\x0b\x32\x30.test_platform.Request.Params.SoftwareAttributes\x12M\n\x13hardware_attributes\x18\x05 \x01(\x0b\x32\x30.test_platform.Request.Params.HardwareAttributes\x12H\n\x11secondary_devices\x18\x06 \x03(\x0b\x32-.test_platform.Request.Params.SecondaryDevice\x1a:\n\x18ProvisionableLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\xc2\x03\n\x04Test\x12K\n\x08\x61utotest\x18\x01 \x01(\x0b\x32\x37.test_platform.skylab_test_runner.Request.Test.AutotestH\x00\x12N\n\x07offload\x18\x02 \x01(\x0b\x32=.test_platform.skylab_test_runner.Request.Test.OffloadOptions\x1a\xe0\x01\n\x08\x41utotest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x11\n\ttest_args\x18\x02 \x01(\t\x12U\n\x07keyvals\x18\x03 \x03(\x0b\x32\x44.test_platform.skylab_test_runner.Request.Test.Autotest.KeyvalsEntry\x12\x16\n\x0eis_client_test\x18\x04 \x01(\x08\x12\x14\n\x0c\x64isplay_name\x18\x05 \x01(\t\x1a.\n\x0cKeyvalsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a/\n\x0eOffloadOptions\x12\x1d\n\x15synchronous_gs_enable\x18\x01 \x01(\x08\x42\t\n\x07harness\x1a\\\n\nTestsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12=\n\x05value\x18\x02 \x01(\x0b\x32..test_platform.skylab_test_runner.Request.Test:\x02\x38\x01\x42LZJgo.chromium.org/chromiumos/infra/proto/go/test_platform/skylab_test_runnerb\x06proto3'
+  serialized_pb=b'\n.test_platform/skylab_test_runner/request.proto\x12 test_platform.skylab_test_runner\x1a-chromiumos/build/api/container_metadata.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a#test_platform/execution/param.proto\x1a\x1btest_platform/request.proto\"\xb5\x0c\n\x07Request\x12@\n\x06prejob\x18\x01 \x01(\x0b\x32\x30.test_platform.skylab_test_runner.Request.Prejob\x12<\n\x04test\x18\x02 \x01(\x0b\x32..test_platform.skylab_test_runner.Request.Test\x12,\n\x08\x64\x65\x61\x64line\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x1a\n\x12parent_request_uid\x18\x04 \x01(\t\x12\x17\n\x0fparent_build_id\x18\x05 \x01(\x03\x12\x43\n\x05tests\x18\x06 \x03(\x0b\x32\x34.test_platform.skylab_test_runner.Request.TestsEntry\x12\x37\n\x0f\x65xecution_param\x18\x07 \x01(\x0b\x32\x1e.test_platform.execution.Param\x12J\n\x14\x63ontainer_image_info\x18\x08 \x01(\x0b\x32(.chromiumos.build.api.ContainerImageInfoB\x02\x18\x01\x12\\\n\x1f\x64\x65\x66\x61ult_test_execution_behavior\x18\t \x01(\x0e\x32\x33.test_platform.Request.Params.TestExecutionBehavior\x1a\xfb\x03\n\x06Prejob\x12O\n\x15software_dependencies\x18\x01 \x03(\x0b\x32\x30.test_platform.Request.Params.SoftwareDependency\x12k\n\x14provisionable_labels\x18\x02 \x03(\x0b\x32I.test_platform.skylab_test_runner.Request.Prejob.ProvisionableLabelsEntryB\x02\x18\x01\x12\x0f\n\x07use_tls\x18\x03 \x01(\x08\x12M\n\x13software_attributes\x18\x04 \x01(\x0b\x32\x30.test_platform.Request.Params.SoftwareAttributes\x12M\n\x13hardware_attributes\x18\x05 \x01(\x0b\x32\x30.test_platform.Request.Params.HardwareAttributes\x12H\n\x11secondary_devices\x18\x06 \x03(\x0b\x32-.test_platform.Request.Params.SecondaryDevice\x1a:\n\x18ProvisionableLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\xc2\x03\n\x04Test\x12K\n\x08\x61utotest\x18\x01 \x01(\x0b\x32\x37.test_platform.skylab_test_runner.Request.Test.AutotestH\x00\x12N\n\x07offload\x18\x02 \x01(\x0b\x32=.test_platform.skylab_test_runner.Request.Test.OffloadOptions\x1a\xe0\x01\n\x08\x41utotest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x11\n\ttest_args\x18\x02 \x01(\t\x12U\n\x07keyvals\x18\x03 \x03(\x0b\x32\x44.test_platform.skylab_test_runner.Request.Test.Autotest.KeyvalsEntry\x12\x16\n\x0eis_client_test\x18\x04 \x01(\x08\x12\x14\n\x0c\x64isplay_name\x18\x05 \x01(\t\x1a.\n\x0cKeyvalsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a/\n\x0eOffloadOptions\x12\x1d\n\x15synchronous_gs_enable\x18\x01 \x01(\x08\x42\t\n\x07harness\x1a\\\n\nTestsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12=\n\x05value\x18\x02 \x01(\x0b\x32..test_platform.skylab_test_runner.Request.Test:\x02\x38\x01\x42LZJgo.chromium.org/chromiumos/infra/proto/go/test_platform/skylab_test_runnerb\x06proto3'
   ,
-  dependencies=[google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,test__platform_dot_execution_dot_param__pb2.DESCRIPTOR,test__platform_dot_request__pb2.DESCRIPTOR,])
+  dependencies=[chromiumos_dot_build_dot_api_dot_container__metadata__pb2.DESCRIPTOR,google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,test__platform_dot_execution_dot_param__pb2.DESCRIPTOR,test__platform_dot_request__pb2.DESCRIPTOR,])
 
 
 
@@ -63,8 +64,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=998,
-  serialized_end=1056,
+  serialized_start=1215,
+  serialized_end=1273,
 )
 
 _REQUEST_PREJOB = _descriptor.Descriptor(
@@ -129,8 +130,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=549,
-  serialized_end=1056,
+  serialized_start=766,
+  serialized_end=1273,
 )
 
 _REQUEST_TEST_AUTOTEST_KEYVALSENTRY = _descriptor.Descriptor(
@@ -167,8 +168,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1403,
-  serialized_end=1449,
+  serialized_start=1620,
+  serialized_end=1666,
 )
 
 _REQUEST_TEST_AUTOTEST = _descriptor.Descriptor(
@@ -226,8 +227,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1225,
-  serialized_end=1449,
+  serialized_start=1442,
+  serialized_end=1666,
 )
 
 _REQUEST_TEST_OFFLOADOPTIONS = _descriptor.Descriptor(
@@ -257,8 +258,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1451,
-  serialized_end=1498,
+  serialized_start=1668,
+  serialized_end=1715,
 )
 
 _REQUEST_TEST = _descriptor.Descriptor(
@@ -300,8 +301,8 @@
       create_key=_descriptor._internal_create_key,
     fields=[]),
   ],
-  serialized_start=1059,
-  serialized_end=1509,
+  serialized_start=1276,
+  serialized_end=1726,
 )
 
 _REQUEST_TESTSENTRY = _descriptor.Descriptor(
@@ -338,8 +339,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1511,
-  serialized_end=1603,
+  serialized_start=1728,
+  serialized_end=1820,
 )
 
 _REQUEST = _descriptor.Descriptor(
@@ -399,6 +400,20 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='container_image_info', full_name='test_platform.skylab_test_runner.Request.container_image_info', index=7,
+      number=8, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=b'\030\001', file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='default_test_execution_behavior', full_name='test_platform.skylab_test_runner.Request.default_test_execution_behavior', index=8,
+      number=9, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -411,8 +426,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=184,
-  serialized_end=1603,
+  serialized_start=231,
+  serialized_end=1820,
 )
 
 _REQUEST_PREJOB_PROVISIONABLELABELSENTRY.containing_type = _REQUEST_PREJOB
@@ -439,6 +454,8 @@
 _REQUEST.fields_by_name['deadline'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP
 _REQUEST.fields_by_name['tests'].message_type = _REQUEST_TESTSENTRY
 _REQUEST.fields_by_name['execution_param'].message_type = test__platform_dot_execution_dot_param__pb2._PARAM
+_REQUEST.fields_by_name['container_image_info'].message_type = chromiumos_dot_build_dot_api_dot_container__metadata__pb2._CONTAINERIMAGEINFO
+_REQUEST.fields_by_name['default_test_execution_behavior'].enum_type = test__platform_dot_request__pb2._REQUEST_PARAMS_TESTEXECUTIONBEHAVIOR
 DESCRIPTOR.message_types_by_name['Request'] = _REQUEST
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
@@ -511,4 +528,5 @@
 _REQUEST_PREJOB.fields_by_name['provisionable_labels']._options = None
 _REQUEST_TEST_AUTOTEST_KEYVALSENTRY._options = None
 _REQUEST_TESTSENTRY._options = None
+_REQUEST.fields_by_name['container_image_info']._options = None
 # @@protoc_insertion_point(module_scope)
diff --git a/api/gen/test_platform/v2/request_pb2.py b/api/gen/test_platform/v2/request_pb2.py
index ec8dc74..bd88018 100644
--- a/api/gen/test_platform/v2/request_pb2.py
+++ b/api/gen/test_platform/v2/request_pb2.py
@@ -12,20 +12,18 @@
 
 
 from chromite.api.gen.chromiumos import common_pb2 as chromiumos_dot_common__pb2
-from chromite.api.gen.chromiumos.test.api import coverage_rule_pb2 as chromiumos_dot_test_dot_api_dot_coverage__rule__pb2
-from chromite.api.gen.chromiumos.test.api import plan_pb2 as chromiumos_dot_test_dot_api_dot_plan__pb2
-from chromite.api.gen.chromiumos.test.api import provision_state_pb2 as chromiumos_dot_test_dot_api_dot_provision__state__pb2
+from chromite.api.gen.chromiumos.test.api.v1 import plan_pb2 as chromiumos_dot_test_dot_api_dot_v1_dot_plan__pb2
 
 
 DESCRIPTOR = _descriptor.FileDescriptor(
   name='test_platform/v2/request.proto',
   package='test_platform.v2',
   syntax='proto3',
-  serialized_options=b'Z:go.chromium.org/chromiumos/infra/proto/go/test_platform/v2',
+  serialized_options=b'ZHgo.chromium.org/chromiumos/infra/proto/go/test_platform/v2;test_platform',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n\x1etest_platform/v2/request.proto\x12\x10test_platform.v2\x1a\x17\x63hromiumos/common.proto\x1a\'chromiumos/test/api/coverage_rule.proto\x1a\x1e\x63hromiumos/test/api/plan.proto\x1a)chromiumos/test/api/provision_state.proto\"y\n\x08TestSpec\x12,\n\x0f\x62uild_directory\x18\x01 \x01(\x0b\x32\x13.chromiumos.GcsPath\x12\x37\n\x0chw_test_plan\x18\x02 \x01(\x0b\x32\x1f.chromiumos.test.api.HWTestPlanH\x00\x42\x06\n\x04spec\"\xe7\x01\n\x07Request\x12,\n\x0f\x62uild_directory\x18\x01 \x01(\x0b\x32\x13.chromiumos.GcsPath\x12.\n\ntest_specs\x18\x02 \x03(\x0b\x32\x1a.test_platform.v2.TestSpec\x12G\n\x12scheduler_settings\x18\x03 \x01(\x0b\x32+.test_platform.v2.Request.SchedulerSettings\x1a\x35\n\x11SchedulerSettings\x12\x0c\n\x04pool\x18\x01 \x01(\t\x12\x12\n\nqs_account\x18\x02 \x01(\tB<Z:go.chromium.org/chromiumos/infra/proto/go/test_platform/v2b\x06proto3'
+  serialized_pb=b'\n\x1etest_platform/v2/request.proto\x12\x10test_platform.v2\x1a\x17\x63hromiumos/common.proto\x1a!chromiumos/test/api/v1/plan.proto\"\x7f\n\x08TestSpec\x12,\n\x0f\x62uild_directory\x18\x01 \x01(\x0b\x32\x13.chromiumos.GcsPath\x12=\n\x0fhw_test_plan_v1\x18\x02 \x01(\x0b\x32\".chromiumos.test.api.v1.HWTestPlanH\x00\x42\x06\n\x04spec\"\xe7\x01\n\x07Request\x12,\n\x0f\x62uild_directory\x18\x01 \x01(\x0b\x32\x13.chromiumos.GcsPath\x12.\n\ntest_specs\x18\x02 \x03(\x0b\x32\x1a.test_platform.v2.TestSpec\x12G\n\x12scheduler_settings\x18\x03 \x01(\x0b\x32+.test_platform.v2.Request.SchedulerSettings\x1a\x35\n\x11SchedulerSettings\x12\x0c\n\x04pool\x18\x01 \x01(\t\x12\x12\n\nqs_account\x18\x02 \x01(\tBJZHgo.chromium.org/chromiumos/infra/proto/go/test_platform/v2;test_platformb\x06proto3'
   ,
-  dependencies=[chromiumos_dot_common__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_coverage__rule__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_plan__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_provision__state__pb2.DESCRIPTOR,])
+  dependencies=[chromiumos_dot_common__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_v1_dot_plan__pb2.DESCRIPTOR,])
 
 
 
@@ -46,7 +44,7 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='hw_test_plan', full_name='test_platform.v2.TestSpec.hw_test_plan', index=1,
+      name='hw_test_plan_v1', full_name='test_platform.v2.TestSpec.hw_test_plan_v1', index=1,
       number=2, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
@@ -69,8 +67,8 @@
       create_key=_descriptor._internal_create_key,
     fields=[]),
   ],
-  serialized_start=193,
-  serialized_end=314,
+  serialized_start=112,
+  serialized_end=239,
 )
 
 
@@ -108,8 +106,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=495,
-  serialized_end=548,
+  serialized_start=420,
+  serialized_end=473,
 )
 
 _REQUEST = _descriptor.Descriptor(
@@ -153,15 +151,15 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=317,
-  serialized_end=548,
+  serialized_start=242,
+  serialized_end=473,
 )
 
 _TESTSPEC.fields_by_name['build_directory'].message_type = chromiumos_dot_common__pb2._GCSPATH
-_TESTSPEC.fields_by_name['hw_test_plan'].message_type = chromiumos_dot_test_dot_api_dot_plan__pb2._HWTESTPLAN
+_TESTSPEC.fields_by_name['hw_test_plan_v1'].message_type = chromiumos_dot_test_dot_api_dot_v1_dot_plan__pb2._HWTESTPLAN
 _TESTSPEC.oneofs_by_name['spec'].fields.append(
-  _TESTSPEC.fields_by_name['hw_test_plan'])
-_TESTSPEC.fields_by_name['hw_test_plan'].containing_oneof = _TESTSPEC.oneofs_by_name['spec']
+  _TESTSPEC.fields_by_name['hw_test_plan_v1'])
+_TESTSPEC.fields_by_name['hw_test_plan_v1'].containing_oneof = _TESTSPEC.oneofs_by_name['spec']
 _REQUEST_SCHEDULERSETTINGS.containing_type = _REQUEST
 _REQUEST.fields_by_name['build_directory'].message_type = chromiumos_dot_common__pb2._GCSPATH
 _REQUEST.fields_by_name['test_specs'].message_type = _TESTSPEC
diff --git a/api/gen_sdk/chromite/api/android_pb2.py b/api/gen_sdk/chromite/api/android_pb2.py
index 18ed073..9ed90a9 100644
--- a/api/gen_sdk/chromite/api/android_pb2.py
+++ b/api/gen_sdk/chromite/api/android_pb2.py
@@ -21,7 +21,7 @@
   package='chromite.api',
   syntax='proto3',
   serialized_options=b'Z6go.chromium.org/chromiumos/infra/proto/go/chromite/api',
-  serialized_pb=b'\n\x1a\x63hromite/api/android.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x17\x63hromiumos/common.proto\"T\n\x15GetLatestBuildRequest\x12\x1c\n\x14\x61ndroid_build_branch\x18\x02 \x01(\t\x12\x17\n\x0f\x61ndroid_package\x18\x03 \x01(\tJ\x04\x08\x01\x10\x02\"1\n\x16GetLatestBuildResponse\x12\x17\n\x0f\x61ndroid_version\x18\x01 \x01(\t\"\x8c\x02\n\x11MarkStableRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x1b\n\x0ftracking_branch\x18\x02 \x01(\tB\x02\x18\x01\x12\x14\n\x0cpackage_name\x18\x03 \x01(\t\x12\x1c\n\x14\x61ndroid_build_branch\x18\x04 \x01(\t\x12\x17\n\x0f\x61ndroid_version\x18\x05 \x01(\t\x12$\n\x18\x61ndroid_gts_build_branch\x18\x06 \x01(\tB\x02\x18\x01\x12.\n\rbuild_targets\x18\x07 \x03(\x0b\x32\x17.chromiumos.BuildTarget\x12\x13\n\x0bskip_commit\x18\x08 \x01(\x08\"w\n\x12MarkStableResponse\x12\x32\n\x06status\x18\x01 \x01(\x0e\x32\".chromite.api.MarkStableStatusType\x12-\n\x0c\x61ndroid_atom\x18\x02 \x01(\x0b\x32\x17.chromiumos.PackageInfo\"9\n\x13UnpinVersionRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x16\n\x14UnpinVersionResponse*\x9c\x01\n\x14MarkStableStatusType\x12\"\n\x1eMARK_STABLE_STATUS_UNSPECIFIED\x10\x00\x12\x1e\n\x1aMARK_STABLE_STATUS_SUCCESS\x10\x01\x12\x1d\n\x19MARK_STABLE_STATUS_PINNED\x10\x02\x12!\n\x1dMARK_STABLE_STATUS_EARLY_EXIT\x10\x03\x32\xbe\x02\n\x0e\x41ndroidService\x12\x63\n\x0eGetLatestBuild\x12#.chromite.api.GetLatestBuildRequest\x1a$.chromite.api.GetLatestBuildResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x12W\n\nMarkStable\x12\x1f.chromite.api.MarkStableRequest\x1a .chromite.api.MarkStableResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x12]\n\x0cUnpinVersion\x12!.chromite.api.UnpinVersionRequest\x1a\".chromite.api.UnpinVersionResponse\"\x06\xc2\xed\x1a\x02\x10\x01\x1a\x0f\xc2\xed\x1a\x0b\n\x07\x61ndroid\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
+  serialized_pb=b'\n\x1a\x63hromite/api/android.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x17\x63hromiumos/common.proto\"T\n\x15GetLatestBuildRequest\x12\x1c\n\x14\x61ndroid_build_branch\x18\x02 \x01(\t\x12\x17\n\x0f\x61ndroid_package\x18\x03 \x01(\tJ\x04\x08\x01\x10\x02\"1\n\x16GetLatestBuildResponse\x12\x17\n\x0f\x61ndroid_version\x18\x01 \x01(\t\"\x8c\x02\n\x11MarkStableRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x1b\n\x0ftracking_branch\x18\x02 \x01(\tB\x02\x18\x01\x12\x14\n\x0cpackage_name\x18\x03 \x01(\t\x12\x1c\n\x14\x61ndroid_build_branch\x18\x04 \x01(\t\x12\x17\n\x0f\x61ndroid_version\x18\x05 \x01(\t\x12$\n\x18\x61ndroid_gts_build_branch\x18\x06 \x01(\tB\x02\x18\x01\x12.\n\rbuild_targets\x18\x07 \x03(\x0b\x32\x17.chromiumos.BuildTarget\x12\x13\n\x0bskip_commit\x18\x08 \x01(\x08\"w\n\x12MarkStableResponse\x12\x32\n\x06status\x18\x01 \x01(\x0e\x32\".chromite.api.MarkStableStatusType\x12-\n\x0c\x61ndroid_atom\x18\x02 \x01(\x0b\x32\x17.chromiumos.PackageInfo\"9\n\x13UnpinVersionRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x16\n\x14UnpinVersionResponse\"D\n\x10WriteLKGBRequest\x12\x17\n\x0f\x61ndroid_package\x18\x01 \x01(\t\x12\x17\n\x0f\x61ndroid_version\x18\x02 \x01(\t\"+\n\x11WriteLKGBResponse\x12\x16\n\x0emodified_files\x18\x01 \x03(\t*\x9c\x01\n\x14MarkStableStatusType\x12\"\n\x1eMARK_STABLE_STATUS_UNSPECIFIED\x10\x00\x12\x1e\n\x1aMARK_STABLE_STATUS_SUCCESS\x10\x01\x12\x1d\n\x19MARK_STABLE_STATUS_PINNED\x10\x02\x12!\n\x1dMARK_STABLE_STATUS_EARLY_EXIT\x10\x03\x32\x94\x03\n\x0e\x41ndroidService\x12\x63\n\x0eGetLatestBuild\x12#.chromite.api.GetLatestBuildRequest\x1a$.chromite.api.GetLatestBuildResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x12W\n\nMarkStable\x12\x1f.chromite.api.MarkStableRequest\x1a .chromite.api.MarkStableResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x12]\n\x0cUnpinVersion\x12!.chromite.api.UnpinVersionRequest\x1a\".chromite.api.UnpinVersionResponse\"\x06\xc2\xed\x1a\x02\x10\x01\x12T\n\tWriteLKGB\x12\x1e.chromite.api.WriteLKGBRequest\x1a\x1f.chromite.api.WriteLKGBResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x1a\x0f\xc2\xed\x1a\x0b\n\x07\x61ndroid\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
   ,
   dependencies=[chromite_dot_api_dot_build__api__pb2.DESCRIPTOR,chromiumos_dot_common__pb2.DESCRIPTOR,])
 
@@ -50,8 +50,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=712,
-  serialized_end=868,
+  serialized_start=827,
+  serialized_end=983,
 )
 _sym_db.RegisterEnumDescriptor(_MARKSTABLESTATUSTYPE)
 
@@ -304,6 +304,75 @@
   serialized_end=709,
 )
 
+
+_WRITELKGBREQUEST = _descriptor.Descriptor(
+  name='WriteLKGBRequest',
+  full_name='chromite.api.WriteLKGBRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='android_package', full_name='chromite.api.WriteLKGBRequest.android_package', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='android_version', full_name='chromite.api.WriteLKGBRequest.android_version', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=711,
+  serialized_end=779,
+)
+
+
+_WRITELKGBRESPONSE = _descriptor.Descriptor(
+  name='WriteLKGBResponse',
+  full_name='chromite.api.WriteLKGBResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='modified_files', full_name='chromite.api.WriteLKGBResponse.modified_files', index=0,
+      number=1, type=9, cpp_type=9, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=781,
+  serialized_end=824,
+)
+
 _MARKSTABLEREQUEST.fields_by_name['chroot'].message_type = chromiumos_dot_common__pb2._CHROOT
 _MARKSTABLEREQUEST.fields_by_name['build_targets'].message_type = chromiumos_dot_common__pb2._BUILDTARGET
 _MARKSTABLERESPONSE.fields_by_name['status'].enum_type = _MARKSTABLESTATUSTYPE
@@ -315,6 +384,8 @@
 DESCRIPTOR.message_types_by_name['MarkStableResponse'] = _MARKSTABLERESPONSE
 DESCRIPTOR.message_types_by_name['UnpinVersionRequest'] = _UNPINVERSIONREQUEST
 DESCRIPTOR.message_types_by_name['UnpinVersionResponse'] = _UNPINVERSIONRESPONSE
+DESCRIPTOR.message_types_by_name['WriteLKGBRequest'] = _WRITELKGBREQUEST
+DESCRIPTOR.message_types_by_name['WriteLKGBResponse'] = _WRITELKGBRESPONSE
 DESCRIPTOR.enum_types_by_name['MarkStableStatusType'] = _MARKSTABLESTATUSTYPE
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
@@ -360,6 +431,20 @@
   })
 _sym_db.RegisterMessage(UnpinVersionResponse)
 
+WriteLKGBRequest = _reflection.GeneratedProtocolMessageType('WriteLKGBRequest', (_message.Message,), {
+  'DESCRIPTOR' : _WRITELKGBREQUEST,
+  '__module__' : 'chromite.api.android_pb2'
+  # @@protoc_insertion_point(class_scope:chromite.api.WriteLKGBRequest)
+  })
+_sym_db.RegisterMessage(WriteLKGBRequest)
+
+WriteLKGBResponse = _reflection.GeneratedProtocolMessageType('WriteLKGBResponse', (_message.Message,), {
+  'DESCRIPTOR' : _WRITELKGBRESPONSE,
+  '__module__' : 'chromite.api.android_pb2'
+  # @@protoc_insertion_point(class_scope:chromite.api.WriteLKGBResponse)
+  })
+_sym_db.RegisterMessage(WriteLKGBResponse)
+
 
 DESCRIPTOR._options = None
 _MARKSTABLEREQUEST.fields_by_name['tracking_branch']._options = None
@@ -371,8 +456,8 @@
   file=DESCRIPTOR,
   index=0,
   serialized_options=b'\302\355\032\013\n\007android\020\001',
-  serialized_start=871,
-  serialized_end=1189,
+  serialized_start=986,
+  serialized_end=1390,
   methods=[
   _descriptor.MethodDescriptor(
     name='GetLatestBuild',
@@ -401,6 +486,15 @@
     output_type=_UNPINVERSIONRESPONSE,
     serialized_options=b'\302\355\032\002\020\001',
   ),
+  _descriptor.MethodDescriptor(
+    name='WriteLKGB',
+    full_name='chromite.api.AndroidService.WriteLKGB',
+    index=3,
+    containing_service=None,
+    input_type=_WRITELKGBREQUEST,
+    output_type=_WRITELKGBRESPONSE,
+    serialized_options=b'\302\355\032\002\020\002',
+  ),
 ])
 _sym_db.RegisterServiceDescriptor(_ANDROIDSERVICE)
 
diff --git a/api/gen_sdk/chromite/api/artifacts_pb2.py b/api/gen_sdk/chromite/api/artifacts_pb2.py
index 45c29d5..8155377 100644
--- a/api/gen_sdk/chromite/api/artifacts_pb2.py
+++ b/api/gen_sdk/chromite/api/artifacts_pb2.py
@@ -21,7 +21,7 @@
   package='chromite.api',
   syntax='proto3',
   serialized_options=b'Z6go.chromium.org/chromiumos/infra/proto/go/chromite/api',
-  serialized_pb=b'\n\x1c\x63hromite/api/artifacts.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x1a\x63hromite/api/sysroot.proto\x1a\x17\x63hromiumos/common.proto\"\x18\n\x08\x41rtifact\x12\x0c\n\x04path\x18\x01 \x01(\t\"W\n\x0b\x44ockerBuild\x12\x12\n\nimage_name\x18\x01 \x01(\t\x12\x18\n\x10\x64ocker_file_path\x18\x02 \x01(\t\x12\x1a\n\x12\x62uild_context_path\x18\x03 \x01(\t\"\xb3\x01\n\x17PrepareForBuildResponse\x12M\n\x0f\x62uild_relevance\x18\x01 \x01(\x0e\x32\x34.chromite.api.PrepareForBuildResponse.BuildRelevance\"I\n\x0e\x42uildRelevance\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\n\n\x06NEEDED\x10\x01\x12\x0b\n\x07UNKNOWN\x10\x02\x12\r\n\tPOINTLESS\x10\x03\"\xb6\x01\n\x11\x42uildSetupRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\x35\n\rartifact_info\x18\x03 \x01(\x0b\x32\x1e.chromiumos.ArtifactsByService\x12\x1e\n\x16\x66orced_build_relevance\x18\x04 \x01(\x08\"\xa9\x01\n\x12\x42uildSetupResponse\x12H\n\x0f\x62uild_relevance\x18\x01 \x01(\x0e\x32/.chromite.api.BuildSetupResponse.BuildRelevance\"I\n\x0e\x42uildRelevance\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\n\n\x06NEEDED\x10\x01\x12\x0b\n\x07UNKNOWN\x10\x02\x12\r\n\tPOINTLESS\x10\x03\"\xbc\x01\n\nGetRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\x35\n\rartifact_info\x18\x03 \x01(\x0b\x32\x1e.chromiumos.ArtifactsByService\x12+\n\x0bresult_path\x18\x04 \x01(\x0b\x32\x16.chromiumos.ResultPath\"H\n\x0bGetResponse\x12\x39\n\tartifacts\x18\x01 \x01(\x0b\x32&.chromiumos.UploadedArtifactsByService\"\xdc\x01\n\x16\x42undleArtifactsRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\x35\n\rartifact_info\x18\x03 \x01(\x0b\x32\x1e.chromiumos.ArtifactsByService\x12\x12\n\noutput_dir\x18\x04 \x01(\t\x12+\n\x0bresult_path\x18\x05 \x01(\x0b\x32\x16.chromiumos.ResultPath\"T\n\x17\x42undleArtifactsResponse\x12\x39\n\tartifacts\x18\x01 \x01(\x0b\x32&.chromiumos.UploadedArtifactsByService\"\x9e\x01\n\rBundleRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x12\n\noutput_dir\x18\x02 \x01(\t\x12\"\n\x06\x63hroot\x18\x03 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x04 \x01(\x0b\x32\x15.chromite.api.Sysroot\"m\n\x0e\x42undleResponse\x12)\n\tartifacts\x18\x01 \x03(\x0b\x32\x16.chromite.api.Artifact\x12\x30\n\rdocker_builds\x18\x02 \x03(\x0b\x32\x19.chromite.api.DockerBuild\"\x90\x01\n\x14\x42undleVmFilesRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\x18\n\x10test_results_dir\x18\x03 \x01(\t\x12\x12\n\noutput_dir\x18\x04 \x01(\t\"\xb5\x01\n\x17\x42undleChromeAFDORequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x12\n\noutput_dir\x18\x03 \x01(\t\x12\x33\n\rartifact_type\x18\x04 \x01(\x0e\x32\x1c.chromiumos.AFDOArtifactType\"h\n\x1aPinnedGuestImageUriRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\"\xa3\x01\n\x1bPinnedGuestImageUriResponse\x12Q\n\rpinned_images\x18\x01 \x03(\x0b\x32:.chromite.api.PinnedGuestImageUriResponse.PinnedGuestImage\x1a\x31\n\x10PinnedGuestImage\x12\x10\n\x08\x66ilename\x18\x01 \x01(\t\x12\x0b\n\x03uri\x18\x02 \x01(\t\"b\n\x14\x46\x65tchMetadataRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\"B\n\x15\x46\x65tchMetadataResponse\x12)\n\tfilepaths\x18\x01 \x03(\x0b\x32\x16.chromiumos.ResultPath2\xad\r\n\x10\x41rtifactsService\x12O\n\nBuildSetup\x12\x1f.chromite.api.BuildSetupRequest\x1a .chromite.api.BuildSetupResponse\x12:\n\x03Get\x12\x18.chromite.api.GetRequest\x1a\x19.chromite.api.GetResponse\x12p\n\x19\x46\x65tchPinnedGuestImageUris\x12(.chromite.api.PinnedGuestImageUriRequest\x1a).chromite.api.PinnedGuestImageUriResponse\x12X\n\rFetchMetadata\x12\".chromite.api.FetchMetadataRequest\x1a#.chromite.api.FetchMetadataResponse\x12P\n\x13\x42undleAutotestFiles\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12Q\n\x14\x42undleChromeOSConfig\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12O\n\x12\x42undleDebugSymbols\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12M\n\x10\x42undleEbuildLogs\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12K\n\x0e\x42undleFirmware\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12P\n\x13\x42undleImageArchives\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12K\n\x0e\x42undleImageZip\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12\x64\n\x1d\x42undleAFDOGenerationArtifacts\x12%.chromite.api.BundleChromeAFDORequest\x1a\x1c.chromite.api.BundleResponse\x12T\n\x17\x42undlePinnedGuestImages\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12X\n\x1b\x42undleSimpleChromeArtifacts\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12L\n\x0f\x42undleTastFiles\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12U\n\x18\x42undleTestUpdatePayloads\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12Q\n\rBundleVmFiles\x12\".chromite.api.BundleVmFilesRequest\x1a\x1c.chromite.api.BundleResponse\x12L\n\x0f\x45xportCpeReport\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12Q\n\x14\x42undleFpmcuUnittests\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12M\n\x10\x42undleGceTarball\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x1a\x11\xc2\xed\x1a\r\n\tartifacts\x10\x02\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
+  serialized_pb=b'\n\x1c\x63hromite/api/artifacts.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x1a\x63hromite/api/sysroot.proto\x1a\x17\x63hromiumos/common.proto\"\x18\n\x08\x41rtifact\x12\x0c\n\x04path\x18\x01 \x01(\t\"W\n\x0b\x44ockerBuild\x12\x12\n\nimage_name\x18\x01 \x01(\t\x12\x18\n\x10\x64ocker_file_path\x18\x02 \x01(\t\x12\x1a\n\x12\x62uild_context_path\x18\x03 \x01(\t\"\xb3\x01\n\x17PrepareForBuildResponse\x12M\n\x0f\x62uild_relevance\x18\x01 \x01(\x0e\x32\x34.chromite.api.PrepareForBuildResponse.BuildRelevance\"I\n\x0e\x42uildRelevance\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\n\n\x06NEEDED\x10\x01\x12\x0b\n\x07UNKNOWN\x10\x02\x12\r\n\tPOINTLESS\x10\x03\"\xb6\x01\n\x11\x42uildSetupRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\x35\n\rartifact_info\x18\x03 \x01(\x0b\x32\x1e.chromiumos.ArtifactsByService\x12\x1e\n\x16\x66orced_build_relevance\x18\x04 \x01(\x08\"\xa9\x01\n\x12\x42uildSetupResponse\x12H\n\x0f\x62uild_relevance\x18\x01 \x01(\x0e\x32/.chromite.api.BuildSetupResponse.BuildRelevance\"I\n\x0e\x42uildRelevance\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\n\n\x06NEEDED\x10\x01\x12\x0b\n\x07UNKNOWN\x10\x02\x12\r\n\tPOINTLESS\x10\x03\"\xbc\x01\n\nGetRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\x35\n\rartifact_info\x18\x03 \x01(\x0b\x32\x1e.chromiumos.ArtifactsByService\x12+\n\x0bresult_path\x18\x04 \x01(\x0b\x32\x16.chromiumos.ResultPath\"H\n\x0bGetResponse\x12\x39\n\tartifacts\x18\x01 \x01(\x0b\x32&.chromiumos.UploadedArtifactsByService\"\xdc\x01\n\x16\x42undleArtifactsRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\x35\n\rartifact_info\x18\x03 \x01(\x0b\x32\x1e.chromiumos.ArtifactsByService\x12\x12\n\noutput_dir\x18\x04 \x01(\t\x12+\n\x0bresult_path\x18\x05 \x01(\x0b\x32\x16.chromiumos.ResultPath\"T\n\x17\x42undleArtifactsResponse\x12\x39\n\tartifacts\x18\x01 \x01(\x0b\x32&.chromiumos.UploadedArtifactsByService\"\x9e\x01\n\rBundleRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x12\n\noutput_dir\x18\x02 \x01(\t\x12\"\n\x06\x63hroot\x18\x03 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x04 \x01(\x0b\x32\x15.chromite.api.Sysroot\"m\n\x0e\x42undleResponse\x12)\n\tartifacts\x18\x01 \x03(\x0b\x32\x16.chromite.api.Artifact\x12\x30\n\rdocker_builds\x18\x02 \x03(\x0b\x32\x19.chromite.api.DockerBuild\"\x90\x01\n\x14\x42undleVmFilesRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\x18\n\x10test_results_dir\x18\x03 \x01(\t\x12\x12\n\noutput_dir\x18\x04 \x01(\t\"h\n\x1aPinnedGuestImageUriRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\"\xa3\x01\n\x1bPinnedGuestImageUriResponse\x12Q\n\rpinned_images\x18\x01 \x03(\x0b\x32:.chromite.api.PinnedGuestImageUriResponse.PinnedGuestImage\x1a\x31\n\x10PinnedGuestImage\x12\x10\n\x08\x66ilename\x18\x01 \x01(\t\x12\x0b\n\x03uri\x18\x02 \x01(\t\"b\n\x14\x46\x65tchMetadataRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\"B\n\x15\x46\x65tchMetadataResponse\x12)\n\tfilepaths\x18\x01 \x03(\x0b\x32\x16.chromiumos.ResultPath2\xc7\x0c\n\x10\x41rtifactsService\x12O\n\nBuildSetup\x12\x1f.chromite.api.BuildSetupRequest\x1a .chromite.api.BuildSetupResponse\x12:\n\x03Get\x12\x18.chromite.api.GetRequest\x1a\x19.chromite.api.GetResponse\x12p\n\x19\x46\x65tchPinnedGuestImageUris\x12(.chromite.api.PinnedGuestImageUriRequest\x1a).chromite.api.PinnedGuestImageUriResponse\x12X\n\rFetchMetadata\x12\".chromite.api.FetchMetadataRequest\x1a#.chromite.api.FetchMetadataResponse\x12P\n\x13\x42undleAutotestFiles\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12Q\n\x14\x42undleChromeOSConfig\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12O\n\x12\x42undleDebugSymbols\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12M\n\x10\x42undleEbuildLogs\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12K\n\x0e\x42undleFirmware\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12P\n\x13\x42undleImageArchives\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12K\n\x0e\x42undleImageZip\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12T\n\x17\x42undlePinnedGuestImages\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12X\n\x1b\x42undleSimpleChromeArtifacts\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12L\n\x0f\x42undleTastFiles\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12U\n\x18\x42undleTestUpdatePayloads\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12Q\n\rBundleVmFiles\x12\".chromite.api.BundleVmFilesRequest\x1a\x1c.chromite.api.BundleResponse\x12L\n\x0f\x45xportCpeReport\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12Q\n\x14\x42undleFpmcuUnittests\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x12M\n\x10\x42undleGceTarball\x12\x1b.chromite.api.BundleRequest\x1a\x1c.chromite.api.BundleResponse\x1a\x11\xc2\xed\x1a\r\n\tartifacts\x10\x02\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
   ,
   dependencies=[chromite_dot_api_dot_build__api__pb2.DESCRIPTOR,chromite_dot_api_dot_sysroot__pb2.DESCRIPTOR,chromiumos_dot_common__pb2.DESCRIPTOR,])
 
@@ -595,58 +595,6 @@
 )
 
 
-_BUNDLECHROMEAFDOREQUEST = _descriptor.Descriptor(
-  name='BundleChromeAFDORequest',
-  full_name='chromite.api.BundleChromeAFDORequest',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='chroot', full_name='chromite.api.BundleChromeAFDORequest.chroot', index=0,
-      number=1, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='build_target', full_name='chromite.api.BundleChromeAFDORequest.build_target', index=1,
-      number=2, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='output_dir', full_name='chromite.api.BundleChromeAFDORequest.output_dir', index=2,
-      number=3, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=b"".decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='artifact_type', full_name='chromite.api.BundleChromeAFDORequest.artifact_type', index=3,
-      number=4, type=14, cpp_type=8, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1777,
-  serialized_end=1958,
-)
-
-
 _PINNEDGUESTIMAGEURIREQUEST = _descriptor.Descriptor(
   name='PinnedGuestImageUriRequest',
   full_name='chromite.api.PinnedGuestImageUriRequest',
@@ -680,8 +628,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1960,
-  serialized_end=2064,
+  serialized_start=1776,
+  serialized_end=1880,
 )
 
 
@@ -718,8 +666,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2181,
-  serialized_end=2230,
+  serialized_start=1997,
+  serialized_end=2046,
 )
 
 _PINNEDGUESTIMAGEURIRESPONSE = _descriptor.Descriptor(
@@ -748,8 +696,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2067,
-  serialized_end=2230,
+  serialized_start=1883,
+  serialized_end=2046,
 )
 
 
@@ -786,8 +734,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2232,
-  serialized_end=2330,
+  serialized_start=2048,
+  serialized_end=2146,
 )
 
 
@@ -817,8 +765,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2332,
-  serialized_end=2398,
+  serialized_start=2148,
+  serialized_end=2214,
 )
 
 _PREPAREFORBUILDRESPONSE.fields_by_name['build_relevance'].enum_type = _PREPAREFORBUILDRESPONSE_BUILDRELEVANCE
@@ -845,9 +793,6 @@
 _BUNDLERESPONSE.fields_by_name['docker_builds'].message_type = _DOCKERBUILD
 _BUNDLEVMFILESREQUEST.fields_by_name['chroot'].message_type = chromiumos_dot_common__pb2._CHROOT
 _BUNDLEVMFILESREQUEST.fields_by_name['sysroot'].message_type = chromite_dot_api_dot_sysroot__pb2._SYSROOT
-_BUNDLECHROMEAFDOREQUEST.fields_by_name['chroot'].message_type = chromiumos_dot_common__pb2._CHROOT
-_BUNDLECHROMEAFDOREQUEST.fields_by_name['build_target'].message_type = chromiumos_dot_common__pb2._BUILDTARGET
-_BUNDLECHROMEAFDOREQUEST.fields_by_name['artifact_type'].enum_type = chromiumos_dot_common__pb2._AFDOARTIFACTTYPE
 _PINNEDGUESTIMAGEURIREQUEST.fields_by_name['chroot'].message_type = chromiumos_dot_common__pb2._CHROOT
 _PINNEDGUESTIMAGEURIREQUEST.fields_by_name['sysroot'].message_type = chromite_dot_api_dot_sysroot__pb2._SYSROOT
 _PINNEDGUESTIMAGEURIRESPONSE_PINNEDGUESTIMAGE.containing_type = _PINNEDGUESTIMAGEURIRESPONSE
@@ -867,7 +812,6 @@
 DESCRIPTOR.message_types_by_name['BundleRequest'] = _BUNDLEREQUEST
 DESCRIPTOR.message_types_by_name['BundleResponse'] = _BUNDLERESPONSE
 DESCRIPTOR.message_types_by_name['BundleVmFilesRequest'] = _BUNDLEVMFILESREQUEST
-DESCRIPTOR.message_types_by_name['BundleChromeAFDORequest'] = _BUNDLECHROMEAFDOREQUEST
 DESCRIPTOR.message_types_by_name['PinnedGuestImageUriRequest'] = _PINNEDGUESTIMAGEURIREQUEST
 DESCRIPTOR.message_types_by_name['PinnedGuestImageUriResponse'] = _PINNEDGUESTIMAGEURIRESPONSE
 DESCRIPTOR.message_types_by_name['FetchMetadataRequest'] = _FETCHMETADATAREQUEST
@@ -958,13 +902,6 @@
   })
 _sym_db.RegisterMessage(BundleVmFilesRequest)
 
-BundleChromeAFDORequest = _reflection.GeneratedProtocolMessageType('BundleChromeAFDORequest', (_message.Message,), {
-  'DESCRIPTOR' : _BUNDLECHROMEAFDOREQUEST,
-  '__module__' : 'chromite.api.artifacts_pb2'
-  # @@protoc_insertion_point(class_scope:chromite.api.BundleChromeAFDORequest)
-  })
-_sym_db.RegisterMessage(BundleChromeAFDORequest)
-
 PinnedGuestImageUriRequest = _reflection.GeneratedProtocolMessageType('PinnedGuestImageUriRequest', (_message.Message,), {
   'DESCRIPTOR' : _PINNEDGUESTIMAGEURIREQUEST,
   '__module__' : 'chromite.api.artifacts_pb2'
@@ -1010,8 +947,8 @@
   file=DESCRIPTOR,
   index=0,
   serialized_options=b'\302\355\032\r\n\tartifacts\020\002',
-  serialized_start=2401,
-  serialized_end=4110,
+  serialized_start=2217,
+  serialized_end=3824,
   methods=[
   _descriptor.MethodDescriptor(
     name='BuildSetup',
@@ -1113,18 +1050,9 @@
     serialized_options=None,
   ),
   _descriptor.MethodDescriptor(
-    name='BundleAFDOGenerationArtifacts',
-    full_name='chromite.api.ArtifactsService.BundleAFDOGenerationArtifacts',
-    index=11,
-    containing_service=None,
-    input_type=_BUNDLECHROMEAFDOREQUEST,
-    output_type=_BUNDLERESPONSE,
-    serialized_options=None,
-  ),
-  _descriptor.MethodDescriptor(
     name='BundlePinnedGuestImages',
     full_name='chromite.api.ArtifactsService.BundlePinnedGuestImages',
-    index=12,
+    index=11,
     containing_service=None,
     input_type=_BUNDLEREQUEST,
     output_type=_BUNDLERESPONSE,
@@ -1133,7 +1061,7 @@
   _descriptor.MethodDescriptor(
     name='BundleSimpleChromeArtifacts',
     full_name='chromite.api.ArtifactsService.BundleSimpleChromeArtifacts',
-    index=13,
+    index=12,
     containing_service=None,
     input_type=_BUNDLEREQUEST,
     output_type=_BUNDLERESPONSE,
@@ -1142,7 +1070,7 @@
   _descriptor.MethodDescriptor(
     name='BundleTastFiles',
     full_name='chromite.api.ArtifactsService.BundleTastFiles',
-    index=14,
+    index=13,
     containing_service=None,
     input_type=_BUNDLEREQUEST,
     output_type=_BUNDLERESPONSE,
@@ -1151,7 +1079,7 @@
   _descriptor.MethodDescriptor(
     name='BundleTestUpdatePayloads',
     full_name='chromite.api.ArtifactsService.BundleTestUpdatePayloads',
-    index=15,
+    index=14,
     containing_service=None,
     input_type=_BUNDLEREQUEST,
     output_type=_BUNDLERESPONSE,
@@ -1160,7 +1088,7 @@
   _descriptor.MethodDescriptor(
     name='BundleVmFiles',
     full_name='chromite.api.ArtifactsService.BundleVmFiles',
-    index=16,
+    index=15,
     containing_service=None,
     input_type=_BUNDLEVMFILESREQUEST,
     output_type=_BUNDLERESPONSE,
@@ -1169,7 +1097,7 @@
   _descriptor.MethodDescriptor(
     name='ExportCpeReport',
     full_name='chromite.api.ArtifactsService.ExportCpeReport',
-    index=17,
+    index=16,
     containing_service=None,
     input_type=_BUNDLEREQUEST,
     output_type=_BUNDLERESPONSE,
@@ -1178,7 +1106,7 @@
   _descriptor.MethodDescriptor(
     name='BundleFpmcuUnittests',
     full_name='chromite.api.ArtifactsService.BundleFpmcuUnittests',
-    index=18,
+    index=17,
     containing_service=None,
     input_type=_BUNDLEREQUEST,
     output_type=_BUNDLERESPONSE,
@@ -1187,7 +1115,7 @@
   _descriptor.MethodDescriptor(
     name='BundleGceTarball',
     full_name='chromite.api.ArtifactsService.BundleGceTarball',
-    index=19,
+    index=18,
     containing_service=None,
     input_type=_BUNDLEREQUEST,
     output_type=_BUNDLERESPONSE,
diff --git a/api/gen_sdk/chromite/api/build_api_test_pb2.py b/api/gen_sdk/chromite/api/build_api_test_pb2.py
index 51b4bd5..7aeab51 100644
--- a/api/gen_sdk/chromite/api/build_api_test_pb2.py
+++ b/api/gen_sdk/chromite/api/build_api_test_pb2.py
@@ -22,7 +22,7 @@
   package='chromite.api',
   syntax='proto3',
   serialized_options=b'Z6go.chromium.org/chromiumos/infra/proto/go/chromite/api',
-  serialized_pb=b'\n!chromite/api/build_api_test.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x17\x63hromiumos/common.proto\x1a\x18\x63hromiumos/metrics.proto\",\n\nNestedPath\x12\x1e\n\x04path\x18\x01 \x01(\x0b\x32\x10.chromiumos.Path\"f\n\x11MultiFieldMessage\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0c\n\x04\x66lag\x18\x03 \x01(\x08\x12)\n\ttest_enum\x18\x04 \x01(\x0e\x32\x16.chromite.api.TestEnum\"\xc9\x04\n\x12TestRequestMessage\x12\n\n\x02id\x18\x01 \x01(\t\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x1e\n\x04path\x18\x03 \x01(\x0b\x32\x10.chromiumos.Path\x12&\n\x0c\x61nother_path\x18\x04 \x01(\x0b\x32\x10.chromiumos.Path\x12-\n\x0bnested_path\x18\x05 \x01(\x0b\x32\x18.chromite.api.NestedPath\x12+\n\x0bresult_path\x18\x06 \x01(\x0b\x32\x16.chromiumos.ResultPath\x12-\n\x0c\x62uild_target\x18\x07 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12.\n\rbuild_targets\x18\x08 \x03(\x0b\x32\x17.chromiumos.BuildTarget\x12)\n\nsynced_dir\x18\t \x01(\x0b\x32\x15.chromiumos.SyncedDir\x12*\n\x0bsynced_dirs\x18\n \x03(\x0b\x32\x15.chromiumos.SyncedDir\x12\x31\n\x08messages\x18\x0b \x03(\x0b\x32\x1f.chromite.api.MultiFieldMessage\x12)\n\ttest_enum\x18\x0c \x01(\x0e\x32\x16.chromite.api.TestEnum\x12*\n\ntest_enums\x18\r \x03(\x0e\x32\x16.chromite.api.TestEnum\x12\x0e\n\x06number\x18\x0e \x01(\x05\x12\x0f\n\x07numbers\x18\x0f \x03(\x05\"\xc8\x01\n\x11TestResultMessage\x12\x0e\n\x06result\x18\x01 \x01(\t\x12\"\n\x08\x61rtifact\x18\x02 \x01(\x0b\x32\x10.chromiumos.Path\x12\x31\n\x0fnested_artifact\x18\x03 \x01(\x0b\x32\x18.chromite.api.NestedPath\x12#\n\tartifacts\x18\x04 \x03(\x0b\x32\x10.chromiumos.Path\x12\'\n\x06\x65vents\x18\x05 \x03(\x0b\x32\x17.chromiumos.MetricEvent*^\n\x08TestEnum\x12\x19\n\x15TEST_ENUM_UNSPECIFIED\x10\x00\x12\x11\n\rTEST_ENUM_FOO\x10\x01\x12\x11\n\rTEST_ENUM_BAR\x10\x02\x12\x11\n\rTEST_ENUM_BAZ\x10\x03\x32\xc0\x02\n\x0eTestApiService\x12V\n\x11InputOutputMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\x12\x65\n\rRenamedMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\"\x11\xc2\xed\x1a\r\n\x0b\x43orrectName\x12Y\n\x0cHiddenMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\"\x06\xc2\xed\x1a\x02\x18\x02\x1a\x14\xc2\xed\x1a\x10\n\x0e\x62uild_api_test2\xf9\x01\n\x16InsideChrootApiService\x12^\n\x19InsideServiceInsideMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\x12g\n\x1aInsideServiceOutsideMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\"\x06\xc2\xed\x1a\x02\x10\x02\x1a\x16\xc2\xed\x1a\x12\n\x0e\x62uild_api_test\x10\x01\x32\xfc\x01\n\x17OutsideChrootApiService\x12`\n\x1bOutsideServiceOutsideMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\x12g\n\x1aOutsideServiceInsideMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\"\x06\xc2\xed\x1a\x02\x10\x01\x1a\x16\xc2\xed\x1a\x12\n\x0e\x62uild_api_test\x10\x02\x32|\n\rHiddenService\x12Q\n\x0cHiddenMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\x1a\x18\xc2\xed\x1a\x14\n\x0e\x62uild_api_test\x10\x02\x18\x02\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
+  serialized_pb=b'\n!chromite/api/build_api_test.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x17\x63hromiumos/common.proto\x1a\x18\x63hromiumos/metrics.proto\",\n\nNestedPath\x12\x1e\n\x04path\x18\x01 \x01(\x0b\x32\x10.chromiumos.Path\"f\n\x11MultiFieldMessage\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0c\n\x04\x66lag\x18\x03 \x01(\x08\x12)\n\ttest_enum\x18\x04 \x01(\x0e\x32\x16.chromite.api.TestEnum\"\x82\x05\n\x12TestRequestMessage\x12\n\n\x02id\x18\x01 \x01(\t\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x1e\n\x04path\x18\x03 \x01(\x0b\x32\x10.chromiumos.Path\x12&\n\x0c\x61nother_path\x18\x04 \x01(\x0b\x32\x10.chromiumos.Path\x12-\n\x0bnested_path\x18\x05 \x01(\x0b\x32\x18.chromite.api.NestedPath\x12+\n\x0bresult_path\x18\x06 \x01(\x0b\x32\x16.chromiumos.ResultPath\x12-\n\x0c\x62uild_target\x18\x07 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12.\n\rbuild_targets\x18\x08 \x03(\x0b\x32\x17.chromiumos.BuildTarget\x12)\n\nsynced_dir\x18\t \x01(\x0b\x32\x15.chromiumos.SyncedDir\x12*\n\x0bsynced_dirs\x18\n \x03(\x0b\x32\x15.chromiumos.SyncedDir\x12\x31\n\x08messages\x18\x0b \x03(\x0b\x32\x1f.chromite.api.MultiFieldMessage\x12)\n\ttest_enum\x18\x0c \x01(\x0e\x32\x16.chromite.api.TestEnum\x12*\n\ntest_enums\x18\r \x03(\x0e\x32\x16.chromite.api.TestEnum\x12\x0e\n\x06number\x18\x0e \x01(\x05\x12\x0f\n\x07numbers\x18\x0f \x03(\x05\x12\x37\n\x11remoteexec_config\x18\x10 \x01(\x0b\x32\x1c.chromiumos.RemoteexecConfig\"\xc8\x01\n\x11TestResultMessage\x12\x0e\n\x06result\x18\x01 \x01(\t\x12\"\n\x08\x61rtifact\x18\x02 \x01(\x0b\x32\x10.chromiumos.Path\x12\x31\n\x0fnested_artifact\x18\x03 \x01(\x0b\x32\x18.chromite.api.NestedPath\x12#\n\tartifacts\x18\x04 \x03(\x0b\x32\x10.chromiumos.Path\x12\'\n\x06\x65vents\x18\x05 \x03(\x0b\x32\x17.chromiumos.MetricEvent*^\n\x08TestEnum\x12\x19\n\x15TEST_ENUM_UNSPECIFIED\x10\x00\x12\x11\n\rTEST_ENUM_FOO\x10\x01\x12\x11\n\rTEST_ENUM_BAR\x10\x02\x12\x11\n\rTEST_ENUM_BAZ\x10\x03\x32\xc0\x02\n\x0eTestApiService\x12V\n\x11InputOutputMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\x12\x65\n\rRenamedMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\"\x11\xc2\xed\x1a\r\n\x0b\x43orrectName\x12Y\n\x0cHiddenMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\"\x06\xc2\xed\x1a\x02\x18\x02\x1a\x14\xc2\xed\x1a\x10\n\x0e\x62uild_api_test2\xf9\x01\n\x16InsideChrootApiService\x12^\n\x19InsideServiceInsideMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\x12g\n\x1aInsideServiceOutsideMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\"\x06\xc2\xed\x1a\x02\x10\x02\x1a\x16\xc2\xed\x1a\x12\n\x0e\x62uild_api_test\x10\x01\x32\xfc\x01\n\x17OutsideChrootApiService\x12`\n\x1bOutsideServiceOutsideMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\x12g\n\x1aOutsideServiceInsideMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\"\x06\xc2\xed\x1a\x02\x10\x01\x1a\x16\xc2\xed\x1a\x12\n\x0e\x62uild_api_test\x10\x02\x32|\n\rHiddenService\x12Q\n\x0cHiddenMethod\x12 .chromite.api.TestRequestMessage\x1a\x1f.chromite.api.TestResultMessage\x1a\x18\xc2\xed\x1a\x14\n\x0e\x62uild_api_test\x10\x02\x18\x02\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
   ,
   dependencies=[chromite_dot_api_dot_build__api__pb2.DESCRIPTOR,chromiumos_dot_common__pb2.DESCRIPTOR,chromiumos_dot_metrics__pb2.DESCRIPTOR,])
 
@@ -51,8 +51,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1073,
-  serialized_end=1167,
+  serialized_start=1130,
+  serialized_end=1224,
 )
 _sym_db.RegisterEnumDescriptor(_TESTENUM)
 
@@ -259,6 +259,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='remoteexec_config', full_name='chromite.api.TestRequestMessage.remoteexec_config', index=15,
+      number=16, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -272,7 +279,7 @@
   oneofs=[
   ],
   serialized_start=283,
-  serialized_end=868,
+  serialized_end=925,
 )
 
 
@@ -330,8 +337,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=871,
-  serialized_end=1071,
+  serialized_start=928,
+  serialized_end=1128,
 )
 
 _NESTEDPATH.fields_by_name['path'].message_type = chromiumos_dot_common__pb2._PATH
@@ -348,6 +355,7 @@
 _TESTREQUESTMESSAGE.fields_by_name['messages'].message_type = _MULTIFIELDMESSAGE
 _TESTREQUESTMESSAGE.fields_by_name['test_enum'].enum_type = _TESTENUM
 _TESTREQUESTMESSAGE.fields_by_name['test_enums'].enum_type = _TESTENUM
+_TESTREQUESTMESSAGE.fields_by_name['remoteexec_config'].message_type = chromiumos_dot_common__pb2._REMOTEEXECCONFIG
 _TESTRESULTMESSAGE.fields_by_name['artifact'].message_type = chromiumos_dot_common__pb2._PATH
 _TESTRESULTMESSAGE.fields_by_name['nested_artifact'].message_type = _NESTEDPATH
 _TESTRESULTMESSAGE.fields_by_name['artifacts'].message_type = chromiumos_dot_common__pb2._PATH
@@ -396,8 +404,8 @@
   file=DESCRIPTOR,
   index=0,
   serialized_options=b'\302\355\032\020\n\016build_api_test',
-  serialized_start=1170,
-  serialized_end=1490,
+  serialized_start=1227,
+  serialized_end=1547,
   methods=[
   _descriptor.MethodDescriptor(
     name='InputOutputMethod',
@@ -438,8 +446,8 @@
   file=DESCRIPTOR,
   index=1,
   serialized_options=b'\302\355\032\022\n\016build_api_test\020\001',
-  serialized_start=1493,
-  serialized_end=1742,
+  serialized_start=1550,
+  serialized_end=1799,
   methods=[
   _descriptor.MethodDescriptor(
     name='InsideServiceInsideMethod',
@@ -471,8 +479,8 @@
   file=DESCRIPTOR,
   index=2,
   serialized_options=b'\302\355\032\022\n\016build_api_test\020\002',
-  serialized_start=1745,
-  serialized_end=1997,
+  serialized_start=1802,
+  serialized_end=2054,
   methods=[
   _descriptor.MethodDescriptor(
     name='OutsideServiceOutsideMethod',
@@ -504,8 +512,8 @@
   file=DESCRIPTOR,
   index=3,
   serialized_options=b'\302\355\032\024\n\016build_api_test\020\002\030\002',
-  serialized_start=1999,
-  serialized_end=2123,
+  serialized_start=2056,
+  serialized_end=2180,
   methods=[
   _descriptor.MethodDescriptor(
     name='HiddenMethod',
diff --git a/api/gen_sdk/chromite/api/firmware_pb2.py b/api/gen_sdk/chromite/api/firmware_pb2.py
index ea0dd47..2af7b61 100644
--- a/api/gen_sdk/chromite/api/firmware_pb2.py
+++ b/api/gen_sdk/chromite/api/firmware_pb2.py
@@ -20,7 +20,7 @@
   package='chromite.api',
   syntax='proto3',
   serialized_options=b'Z6go.chromium.org/chromiumos/infra/proto/go/chromite/api',
-  serialized_pb=b'\n\x1b\x63hromite/api/firmware.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x17\x63hromiumos/common.proto\"(\n\x0e\x42\x63sVersionInfo\x12\x16\n\x0eversion_string\x18\x01 \x01(\t\"-\n\x13\x46irmwareVersionInfo\x12\x16\n\x0eversion_string\x18\x01 \x01(\t\"\xfe\x02\n\rFwBuildMetric\x12\x13\n\x0btarget_name\x18\x01 \x01(\t\x12\x15\n\rplatform_name\x18\x02 \x01(\t\x12\x39\n\nfw_section\x18\x03 \x03(\x0b\x32%.chromite.api.FwBuildMetric.FwSection\x12:\n\x06zephyr\x18\x04 \x01(\x0b\x32(.chromite.api.FwBuildMetric.ZephyrTargetH\x00\x1a\x38\n\tFwSection\x12\x0e\n\x06region\x18\x01 \x01(\t\x12\x0c\n\x04used\x18\x02 \x01(\r\x12\r\n\x05total\x18\x03 \x01(\r\x1a\x35\n\x07Version\x12\r\n\x05major\x18\x01 \x01(\r\x12\r\n\x05minor\x18\x02 \x01(\r\x12\x0c\n\x04tiny\x18\x03 \x01(\r\x1aK\n\x0cZephyrTarget\x12;\n\x0ekernel_version\x18\x01 \x01(\x0b\x32#.chromite.api.FwBuildMetric.VersionB\x0c\n\nimage_type\"?\n\x11\x46wBuildMetricList\x12*\n\x05value\x18\x01 \x03(\x0b\x32\x1b.chromite.api.FwBuildMetric\"\x1c\n\x0c\x46wTestMetric\x12\x0c\n\x04name\x18\x01 \x01(\t\"=\n\x10\x46wTestMetricList\x12)\n\x05value\x18\x01 \x03(\x0b\x32\x1a.chromite.api.FwTestMetric\"\x87\x01\n\x17\x42uildAllFirmwareRequest\x12\x31\n\x11\x66irmware_location\x18\x01 \x01(\x0e\x32\x16.chromiumos.FwLocation\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x15\n\rcode_coverage\x18\x03 \x01(\x08\"L\n\x18\x42uildAllFirmwareResponse\x12\x30\n\x07metrics\x18\x01 \x01(\x0b\x32\x1f.chromite.api.FwBuildMetricList\"\x86\x01\n\x16TestAllFirmwareRequest\x12\x31\n\x11\x66irmware_location\x18\x01 \x01(\x0e\x32\x16.chromiumos.FwLocation\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x15\n\rcode_coverage\x18\x03 \x01(\x08\"J\n\x17TestAllFirmwareResponse\x12/\n\x07metrics\x18\x01 \x01(\x0b\x32\x1e.chromite.api.FwTestMetricList\"\xfe\x01\n\x1e\x42undleFirmwareArtifactsRequest\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12+\n\x0bresult_path\x18\x03 \x01(\x0b\x32\x16.chromiumos.ResultPath\x12:\n\tartifacts\x18\x04 \x01(\x0b\x32\'.chromiumos.ArtifactsByService.Firmware\x12\x17\n\x0b\x62\x63s_version\x18\x05 \x01(\tB\x02\x18\x01\x12\x36\n\x10\x62\x63s_version_info\x18\x06 \x01(\x0b\x32\x1c.chromite.api.BcsVersionInfo\"e\n\x1f\x42undleFirmwareArtifactsResponse\x12\x42\n\tartifacts\x18\x01 \x01(\x0b\x32/.chromiumos.UploadedArtifactsByService.Firmware\"\xf5\x06\n\x14\x46irmwareArtifactInfo\x12>\n\x07objects\x18\x01 \x03(\x0b\x32-.chromite.api.FirmwareArtifactInfo.ObjectInfo\x12\x36\n\x10\x62\x63s_version_info\x18\x02 \x01(\x0b\x32\x1c.chromite.api.BcsVersionInfo\x1a\x8a\x03\n\x0bTarballInfo\x12\x17\n\x0b\x62\x63s_version\x18\x01 \x01(\tB\x02\x18\x01\x12\x1b\n\x13\x66irmware_image_name\x18\x02 \x01(\t\x12N\n\x04type\x18\x03 \x01(\x0e\x32@.chromite.api.FirmwareArtifactInfo.TarballInfo.FirmwareType.Type\x12K\n\x07version\x18\x04 \x01(\x0b\x32\x36.chromite.api.FirmwareArtifactInfo.TarballInfo.VersionB\x02\x18\x01\x12@\n\x15\x66irmware_version_info\x18\x05 \x01(\x0b\x32!.chromite.api.FirmwareVersionInfo\x1a=\n\x0c\x46irmwareType\"-\n\x04Type\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x08\n\x04MAIN\x10\x01\x12\x06\n\x02\x45\x43\x10\x02\x12\x06\n\x02PD\x10\x03\x1a\'\n\x07Version\x12\r\n\x05major\x18\x01 \x01(\x05\x12\r\n\x05minor\x18\x02 \x01(\x05\x1a\x8c\x01\n\x0fLcovTarballInfo\x12N\n\x04type\x18\x01 \x01(\x0e\x32@.chromite.api.FirmwareArtifactInfo.LcovTarballInfo.LcovType.Type\x1a)\n\x08LcovType\"\x1d\n\x04Type\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x08\n\x04LCOV\x10\x01\x1a\xc8\x01\n\nObjectInfo\x12\x11\n\tfile_name\x18\x01 \x01(\t\x12\x46\n\x0ctarball_info\x18\x02 \x01(\x0b\x32..chromite.api.FirmwareArtifactInfo.TarballInfoH\x00\x12G\n\tlcov_info\x18\x03 \x01(\x0b\x32\x32.chromite.api.FirmwareArtifactInfo.LcovTarballInfoH\x00\x42\x16\n\x14\x66irmware_object_info2\xde\x02\n\x0f\x46irmwareService\x12\x61\n\x10\x42uildAllFirmware\x12%.chromite.api.BuildAllFirmwareRequest\x1a&.chromite.api.BuildAllFirmwareResponse\x12^\n\x0fTestAllFirmware\x12$.chromite.api.TestAllFirmwareRequest\x1a%.chromite.api.TestAllFirmwareResponse\x12v\n\x17\x42undleFirmwareArtifacts\x12,.chromite.api.BundleFirmwareArtifactsRequest\x1a-.chromite.api.BundleFirmwareArtifactsResponse\x1a\x10\xc2\xed\x1a\x0c\n\x08\x66irmware\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
+  serialized_pb=b'\n\x1b\x63hromite/api/firmware.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x17\x63hromiumos/common.proto\"(\n\x0e\x42\x63sVersionInfo\x12\x16\n\x0eversion_string\x18\x01 \x01(\t\"-\n\x13\x46irmwareVersionInfo\x12\x16\n\x0eversion_string\x18\x01 \x01(\t\"\x97\x03\n\rFwBuildMetric\x12\x13\n\x0btarget_name\x18\x01 \x01(\t\x12\x15\n\rplatform_name\x18\x02 \x01(\t\x12\x39\n\nfw_section\x18\x03 \x03(\x0b\x32%.chromite.api.FwBuildMetric.FwSection\x12:\n\x06zephyr\x18\x04 \x01(\x0b\x32(.chromite.api.FwBuildMetric.ZephyrTargetH\x00\x1aQ\n\tFwSection\x12\x0e\n\x06region\x18\x01 \x01(\t\x12\x0c\n\x04used\x18\x02 \x01(\r\x12\r\n\x05total\x18\x03 \x01(\r\x12\x17\n\x0ftrack_on_gerrit\x18\x04 \x01(\x08\x1a\x35\n\x07Version\x12\r\n\x05major\x18\x01 \x01(\r\x12\r\n\x05minor\x18\x02 \x01(\r\x12\x0c\n\x04tiny\x18\x03 \x01(\r\x1aK\n\x0cZephyrTarget\x12;\n\x0ekernel_version\x18\x01 \x01(\x0b\x32#.chromite.api.FwBuildMetric.VersionB\x0c\n\nimage_type\"?\n\x11\x46wBuildMetricList\x12*\n\x05value\x18\x01 \x03(\x0b\x32\x1b.chromite.api.FwBuildMetric\"\x1c\n\x0c\x46wTestMetric\x12\x0c\n\x04name\x18\x01 \x01(\t\"=\n\x10\x46wTestMetricList\x12)\n\x05value\x18\x01 \x03(\x0b\x32\x1a.chromite.api.FwTestMetric\"\x87\x01\n\x17\x42uildAllFirmwareRequest\x12\x31\n\x11\x66irmware_location\x18\x01 \x01(\x0e\x32\x16.chromiumos.FwLocation\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x15\n\rcode_coverage\x18\x03 \x01(\x08\"L\n\x18\x42uildAllFirmwareResponse\x12\x30\n\x07metrics\x18\x01 \x01(\x0b\x32\x1f.chromite.api.FwBuildMetricList\"\x86\x01\n\x16TestAllFirmwareRequest\x12\x31\n\x11\x66irmware_location\x18\x01 \x01(\x0e\x32\x16.chromiumos.FwLocation\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x15\n\rcode_coverage\x18\x03 \x01(\x08\"J\n\x17TestAllFirmwareResponse\x12/\n\x07metrics\x18\x01 \x01(\x0b\x32\x1e.chromite.api.FwTestMetricList\"\xfe\x01\n\x1e\x42undleFirmwareArtifactsRequest\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12+\n\x0bresult_path\x18\x03 \x01(\x0b\x32\x16.chromiumos.ResultPath\x12:\n\tartifacts\x18\x04 \x01(\x0b\x32\'.chromiumos.ArtifactsByService.Firmware\x12\x17\n\x0b\x62\x63s_version\x18\x05 \x01(\tB\x02\x18\x01\x12\x36\n\x10\x62\x63s_version_info\x18\x06 \x01(\x0b\x32\x1c.chromite.api.BcsVersionInfo\"e\n\x1f\x42undleFirmwareArtifactsResponse\x12\x42\n\tartifacts\x18\x01 \x01(\x0b\x32/.chromiumos.UploadedArtifactsByService.Firmware\"\xf5\x06\n\x14\x46irmwareArtifactInfo\x12>\n\x07objects\x18\x01 \x03(\x0b\x32-.chromite.api.FirmwareArtifactInfo.ObjectInfo\x12\x36\n\x10\x62\x63s_version_info\x18\x02 \x01(\x0b\x32\x1c.chromite.api.BcsVersionInfo\x1a\x8a\x03\n\x0bTarballInfo\x12\x17\n\x0b\x62\x63s_version\x18\x01 \x01(\tB\x02\x18\x01\x12\x1b\n\x13\x66irmware_image_name\x18\x02 \x01(\t\x12N\n\x04type\x18\x03 \x01(\x0e\x32@.chromite.api.FirmwareArtifactInfo.TarballInfo.FirmwareType.Type\x12K\n\x07version\x18\x04 \x01(\x0b\x32\x36.chromite.api.FirmwareArtifactInfo.TarballInfo.VersionB\x02\x18\x01\x12@\n\x15\x66irmware_version_info\x18\x05 \x01(\x0b\x32!.chromite.api.FirmwareVersionInfo\x1a=\n\x0c\x46irmwareType\"-\n\x04Type\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x08\n\x04MAIN\x10\x01\x12\x06\n\x02\x45\x43\x10\x02\x12\x06\n\x02PD\x10\x03\x1a\'\n\x07Version\x12\r\n\x05major\x18\x01 \x01(\x05\x12\r\n\x05minor\x18\x02 \x01(\x05\x1a\x8c\x01\n\x0fLcovTarballInfo\x12N\n\x04type\x18\x01 \x01(\x0e\x32@.chromite.api.FirmwareArtifactInfo.LcovTarballInfo.LcovType.Type\x1a)\n\x08LcovType\"\x1d\n\x04Type\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x08\n\x04LCOV\x10\x01\x1a\xc8\x01\n\nObjectInfo\x12\x11\n\tfile_name\x18\x01 \x01(\t\x12\x46\n\x0ctarball_info\x18\x02 \x01(\x0b\x32..chromite.api.FirmwareArtifactInfo.TarballInfoH\x00\x12G\n\tlcov_info\x18\x03 \x01(\x0b\x32\x32.chromite.api.FirmwareArtifactInfo.LcovTarballInfoH\x00\x42\x16\n\x14\x66irmware_object_info2\xde\x02\n\x0f\x46irmwareService\x12\x61\n\x10\x42uildAllFirmware\x12%.chromite.api.BuildAllFirmwareRequest\x1a&.chromite.api.BuildAllFirmwareResponse\x12^\n\x0fTestAllFirmware\x12$.chromite.api.TestAllFirmwareRequest\x1a%.chromite.api.TestAllFirmwareResponse\x12v\n\x17\x42undleFirmwareArtifacts\x12,.chromite.api.BundleFirmwareArtifactsRequest\x1a-.chromite.api.BundleFirmwareArtifactsResponse\x1a\x10\xc2\xed\x1a\x0c\n\x08\x66irmware\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
   ,
   dependencies=[chromite_dot_api_dot_build__api__pb2.DESCRIPTOR,chromiumos_dot_common__pb2.DESCRIPTOR,])
 
@@ -51,8 +51,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1975,
-  serialized_end=2020,
+  serialized_start=2000,
+  serialized_end=2045,
 )
 _sym_db.RegisterEnumDescriptor(_FIRMWAREARTIFACTINFO_TARBALLINFO_FIRMWARETYPE_TYPE)
 
@@ -73,8 +73,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2175,
-  serialized_end=2204,
+  serialized_start=2200,
+  serialized_end=2229,
 )
 _sym_db.RegisterEnumDescriptor(_FIRMWAREARTIFACTINFO_LCOVTARBALLINFO_LCOVTYPE_TYPE)
 
@@ -169,6 +169,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='track_on_gerrit', full_name='chromite.api.FwBuildMetric.FwSection.track_on_gerrit', index=3,
+      number=4, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -182,7 +189,7 @@
   oneofs=[
   ],
   serialized_start=370,
-  serialized_end=426,
+  serialized_end=451,
 )
 
 _FWBUILDMETRIC_VERSION = _descriptor.Descriptor(
@@ -225,8 +232,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=428,
-  serialized_end=481,
+  serialized_start=453,
+  serialized_end=506,
 )
 
 _FWBUILDMETRIC_ZEPHYRTARGET = _descriptor.Descriptor(
@@ -255,8 +262,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=483,
-  serialized_end=558,
+  serialized_start=508,
+  serialized_end=583,
 )
 
 _FWBUILDMETRIC = _descriptor.Descriptor(
@@ -310,7 +317,7 @@
       index=0, containing_type=None, fields=[]),
   ],
   serialized_start=190,
-  serialized_end=572,
+  serialized_end=597,
 )
 
 
@@ -340,8 +347,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=574,
-  serialized_end=637,
+  serialized_start=599,
+  serialized_end=662,
 )
 
 
@@ -371,8 +378,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=639,
-  serialized_end=667,
+  serialized_start=664,
+  serialized_end=692,
 )
 
 
@@ -402,8 +409,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=669,
-  serialized_end=730,
+  serialized_start=694,
+  serialized_end=755,
 )
 
 
@@ -447,8 +454,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=733,
-  serialized_end=868,
+  serialized_start=758,
+  serialized_end=893,
 )
 
 
@@ -478,8 +485,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=870,
-  serialized_end=946,
+  serialized_start=895,
+  serialized_end=971,
 )
 
 
@@ -523,8 +530,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=949,
-  serialized_end=1083,
+  serialized_start=974,
+  serialized_end=1108,
 )
 
 
@@ -554,8 +561,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1085,
-  serialized_end=1159,
+  serialized_start=1110,
+  serialized_end=1184,
 )
 
 
@@ -613,8 +620,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1162,
-  serialized_end=1416,
+  serialized_start=1187,
+  serialized_end=1441,
 )
 
 
@@ -644,8 +651,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1418,
-  serialized_end=1519,
+  serialized_start=1443,
+  serialized_end=1544,
 )
 
 
@@ -669,8 +676,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1959,
-  serialized_end=2020,
+  serialized_start=1984,
+  serialized_end=2045,
 )
 
 _FIRMWAREARTIFACTINFO_TARBALLINFO_VERSION = _descriptor.Descriptor(
@@ -706,8 +713,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2022,
-  serialized_end=2061,
+  serialized_start=2047,
+  serialized_end=2086,
 )
 
 _FIRMWAREARTIFACTINFO_TARBALLINFO = _descriptor.Descriptor(
@@ -764,8 +771,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1667,
-  serialized_end=2061,
+  serialized_start=1692,
+  serialized_end=2086,
 )
 
 _FIRMWAREARTIFACTINFO_LCOVTARBALLINFO_LCOVTYPE = _descriptor.Descriptor(
@@ -788,8 +795,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2163,
-  serialized_end=2204,
+  serialized_start=2188,
+  serialized_end=2229,
 )
 
 _FIRMWAREARTIFACTINFO_LCOVTARBALLINFO = _descriptor.Descriptor(
@@ -818,8 +825,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2064,
-  serialized_end=2204,
+  serialized_start=2089,
+  serialized_end=2229,
 )
 
 _FIRMWAREARTIFACTINFO_OBJECTINFO = _descriptor.Descriptor(
@@ -865,8 +872,8 @@
       name='firmware_object_info', full_name='chromite.api.FirmwareArtifactInfo.ObjectInfo.firmware_object_info',
       index=0, containing_type=None, fields=[]),
   ],
-  serialized_start=2207,
-  serialized_end=2407,
+  serialized_start=2232,
+  serialized_end=2432,
 )
 
 _FIRMWAREARTIFACTINFO = _descriptor.Descriptor(
@@ -902,8 +909,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1522,
-  serialized_end=2407,
+  serialized_start=1547,
+  serialized_end=2432,
 )
 
 _FWBUILDMETRIC_FWSECTION.containing_type = _FWBUILDMETRIC
@@ -1140,8 +1147,8 @@
   file=DESCRIPTOR,
   index=0,
   serialized_options=b'\302\355\032\014\n\010firmware\020\001',
-  serialized_start=2410,
-  serialized_end=2760,
+  serialized_start=2435,
+  serialized_end=2785,
   methods=[
   _descriptor.MethodDescriptor(
     name='BuildAllFirmware',
diff --git a/api/gen_sdk/chromite/api/image_pb2.py b/api/gen_sdk/chromite/api/image_pb2.py
index 9d44325..93f90c3 100644
--- a/api/gen_sdk/chromite/api/image_pb2.py
+++ b/api/gen_sdk/chromite/api/image_pb2.py
@@ -22,7 +22,7 @@
   package='chromite.api',
   syntax='proto3',
   serialized_options=b'Z6go.chromium.org/chromiumos/infra/proto/go/chromite/api',
-  serialized_pb=b'\n\x18\x63hromite/api/image.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x1a\x63hromite/api/sysroot.proto\x1a\x17\x63hromiumos/common.proto\x1a\x18\x63hromiumos/metrics.proto\"i\n\x05Image\x12\x0c\n\x04path\x18\x01 \x01(\t\x12#\n\x04type\x18\x02 \x01(\x0e\x32\x15.chromiumos.ImageType\x12-\n\x0c\x62uild_target\x18\x03 \x01(\x0b\x32\x17.chromiumos.BuildTarget\"\xf4\x01\n\x12\x43reateImageRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12*\n\x0bimage_types\x18\x02 \x03(\x0e\x32\x15.chromiumos.ImageType\x12#\n\x1b\x64isable_rootfs_verification\x18\x03 \x01(\x08\x12\x0f\n\x07version\x18\x04 \x01(\t\x12\x13\n\x0b\x64isk_layout\x18\x05 \x01(\t\x12\x14\n\x0c\x62uilder_path\x18\x06 \x01(\t\x12\"\n\x06\x63hroot\x18\x07 \x01(\x0b\x32\x12.chromiumos.Chroot\"\xa4\x01\n\x11\x43reateImageResult\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12#\n\x06images\x18\x02 \x03(\x0b\x32\x13.chromite.api.Image\x12\x30\n\x0f\x66\x61iled_packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\'\n\x06\x65vents\x18\x04 \x03(\x0b\x32\x17.chromiumos.MetricEvent\"\xdd\x01\n\x10TestImageRequest\x12\"\n\x05image\x18\x01 \x01(\x0b\x32\x13.chromite.api.Image\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x35\n\x06result\x18\x03 \x01(\x0b\x32%.chromite.api.TestImageRequest.Result\x12\"\n\x06\x63hroot\x18\x04 \x01(\x0b\x32\x12.chromiumos.Chroot\x1a\x1b\n\x06Result\x12\x11\n\tdirectory\x18\x01 \x01(\t\"\"\n\x0fTestImageResult\x12\x0f\n\x07success\x18\x01 \x01(\x08\"\xa5\x02\n\x10PushImageRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x0e\n\x06\x64ryrun\x18\x02 \x01(\x08\x12\x14\n\x0cgs_image_dir\x18\x03 \x01(\t\x12&\n\x07sysroot\x18\x04 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12$\n\x07profile\x18\x05 \x01(\x0b\x32\x13.chromiumos.Profile\x12)\n\nsign_types\x18\x06 \x03(\x0e\x32\x15.chromiumos.ImageType\x12\x13\n\x0b\x64\x65st_bucket\x18\x07 \x01(\t\x12\x12\n\nis_staging\x18\x08 \x01(\x08\x12%\n\x08\x63hannels\x18\t \x03(\x0e\x32\x13.chromiumos.Channel\"\x13\n\x11PushImageResponse2\xcc\x02\n\x0cImageService\x12K\n\x06\x43reate\x12 .chromite.api.CreateImageRequest\x1a\x1f.chromite.api.CreateImageResult\x12\x45\n\x04Test\x12\x1e.chromite.api.TestImageRequest\x1a\x1d.chromite.api.TestImageResult\x12K\n\nSignerTest\x12\x1e.chromite.api.TestImageRequest\x1a\x1d.chromite.api.TestImageResult\x12L\n\tPushImage\x12\x1e.chromite.api.PushImageRequest\x1a\x1f.chromite.api.PushImageResponse\x1a\r\xc2\xed\x1a\t\n\x05image\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
+  serialized_pb=b'\n\x18\x63hromite/api/image.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x1a\x63hromite/api/sysroot.proto\x1a\x17\x63hromiumos/common.proto\x1a\x18\x63hromiumos/metrics.proto\"i\n\x05Image\x12\x0c\n\x04path\x18\x01 \x01(\t\x12#\n\x04type\x18\x02 \x01(\x0e\x32\x15.chromiumos.ImageType\x12-\n\x0c\x62uild_target\x18\x03 \x01(\x0b\x32\x17.chromiumos.BuildTarget\"\xf4\x01\n\x12\x43reateImageRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12*\n\x0bimage_types\x18\x02 \x03(\x0e\x32\x15.chromiumos.ImageType\x12#\n\x1b\x64isable_rootfs_verification\x18\x03 \x01(\x08\x12\x0f\n\x07version\x18\x04 \x01(\t\x12\x13\n\x0b\x64isk_layout\x18\x05 \x01(\t\x12\x14\n\x0c\x62uilder_path\x18\x06 \x01(\t\x12\"\n\x06\x63hroot\x18\x07 \x01(\x0b\x32\x12.chromiumos.Chroot\"\xa4\x01\n\x11\x43reateImageResult\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12#\n\x06images\x18\x02 \x03(\x0b\x32\x13.chromite.api.Image\x12\x30\n\x0f\x66\x61iled_packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\'\n\x06\x65vents\x18\x04 \x03(\x0b\x32\x17.chromiumos.MetricEvent\"\xdd\x01\n\x10TestImageRequest\x12\"\n\x05image\x18\x01 \x01(\x0b\x32\x13.chromite.api.Image\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x35\n\x06result\x18\x03 \x01(\x0b\x32%.chromite.api.TestImageRequest.Result\x12\"\n\x06\x63hroot\x18\x04 \x01(\x0b\x32\x12.chromiumos.Chroot\x1a\x1b\n\x06Result\x12\x11\n\tdirectory\x18\x01 \x01(\t\"\"\n\x0fTestImageResult\x12\x0f\n\x07success\x18\x01 \x01(\x08\"\xa5\x02\n\x10PushImageRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x0e\n\x06\x64ryrun\x18\x02 \x01(\x08\x12\x14\n\x0cgs_image_dir\x18\x03 \x01(\t\x12&\n\x07sysroot\x18\x04 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12$\n\x07profile\x18\x05 \x01(\x0b\x32\x13.chromiumos.Profile\x12)\n\nsign_types\x18\x06 \x03(\x0e\x32\x15.chromiumos.ImageType\x12\x13\n\x0b\x64\x65st_bucket\x18\x07 \x01(\t\x12\x12\n\nis_staging\x18\x08 \x01(\x08\x12%\n\x08\x63hannels\x18\t \x03(\x0e\x32\x13.chromiumos.Channel\"\x87\x01\n\x11PushImageResponse\x12\x42\n\x0cinstructions\x18\x01 \x03(\x0b\x32,.chromite.api.PushImageResponse.Instructions\x1a.\n\x0cInstructions\x12\x1e\n\x16instructions_file_path\x18\x01 \x01(\t2\xcc\x02\n\x0cImageService\x12K\n\x06\x43reate\x12 .chromite.api.CreateImageRequest\x1a\x1f.chromite.api.CreateImageResult\x12\x45\n\x04Test\x12\x1e.chromite.api.TestImageRequest\x1a\x1d.chromite.api.TestImageResult\x12K\n\nSignerTest\x12\x1e.chromite.api.TestImageRequest\x1a\x1d.chromite.api.TestImageResult\x12L\n\tPushImage\x12\x1e.chromite.api.PushImageRequest\x1a\x1f.chromite.api.PushImageResponse\x1a\r\xc2\xed\x1a\t\n\x05image\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
   ,
   dependencies=[chromite_dot_api_dot_build__api__pb2.DESCRIPTOR,chromite_dot_api_dot_sysroot__pb2.DESCRIPTOR,chromiumos_dot_common__pb2.DESCRIPTOR,chromiumos_dot_metrics__pb2.DESCRIPTOR,])
 
@@ -399,13 +399,20 @@
 )
 
 
-_PUSHIMAGERESPONSE = _descriptor.Descriptor(
-  name='PushImageResponse',
-  full_name='chromite.api.PushImageResponse',
+_PUSHIMAGERESPONSE_INSTRUCTIONS = _descriptor.Descriptor(
+  name='Instructions',
+  full_name='chromite.api.PushImageResponse.Instructions',
   filename=None,
   file=DESCRIPTOR,
   containing_type=None,
   fields=[
+    _descriptor.FieldDescriptor(
+      name='instructions_file_path', full_name='chromite.api.PushImageResponse.Instructions.instructions_file_path', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -418,8 +425,38 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1228,
-  serialized_end=1247,
+  serialized_start=1318,
+  serialized_end=1364,
+)
+
+_PUSHIMAGERESPONSE = _descriptor.Descriptor(
+  name='PushImageResponse',
+  full_name='chromite.api.PushImageResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='instructions', full_name='chromite.api.PushImageResponse.instructions', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[_PUSHIMAGERESPONSE_INSTRUCTIONS, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1229,
+  serialized_end=1364,
 )
 
 _IMAGE.fields_by_name['type'].enum_type = chromiumos_dot_common__pb2._IMAGETYPE
@@ -440,6 +477,8 @@
 _PUSHIMAGEREQUEST.fields_by_name['profile'].message_type = chromiumos_dot_common__pb2._PROFILE
 _PUSHIMAGEREQUEST.fields_by_name['sign_types'].enum_type = chromiumos_dot_common__pb2._IMAGETYPE
 _PUSHIMAGEREQUEST.fields_by_name['channels'].enum_type = chromiumos_dot_common__pb2._CHANNEL
+_PUSHIMAGERESPONSE_INSTRUCTIONS.containing_type = _PUSHIMAGERESPONSE
+_PUSHIMAGERESPONSE.fields_by_name['instructions'].message_type = _PUSHIMAGERESPONSE_INSTRUCTIONS
 DESCRIPTOR.message_types_by_name['Image'] = _IMAGE
 DESCRIPTOR.message_types_by_name['CreateImageRequest'] = _CREATEIMAGEREQUEST
 DESCRIPTOR.message_types_by_name['CreateImageResult'] = _CREATEIMAGERESULT
@@ -500,11 +539,19 @@
 _sym_db.RegisterMessage(PushImageRequest)
 
 PushImageResponse = _reflection.GeneratedProtocolMessageType('PushImageResponse', (_message.Message,), {
+
+  'Instructions' : _reflection.GeneratedProtocolMessageType('Instructions', (_message.Message,), {
+    'DESCRIPTOR' : _PUSHIMAGERESPONSE_INSTRUCTIONS,
+    '__module__' : 'chromite.api.image_pb2'
+    # @@protoc_insertion_point(class_scope:chromite.api.PushImageResponse.Instructions)
+    })
+  ,
   'DESCRIPTOR' : _PUSHIMAGERESPONSE,
   '__module__' : 'chromite.api.image_pb2'
   # @@protoc_insertion_point(class_scope:chromite.api.PushImageResponse)
   })
 _sym_db.RegisterMessage(PushImageResponse)
+_sym_db.RegisterMessage(PushImageResponse.Instructions)
 
 
 DESCRIPTOR._options = None
@@ -515,8 +562,8 @@
   file=DESCRIPTOR,
   index=0,
   serialized_options=b'\302\355\032\t\n\005image\020\001',
-  serialized_start=1250,
-  serialized_end=1582,
+  serialized_start=1367,
+  serialized_end=1699,
   methods=[
   _descriptor.MethodDescriptor(
     name='Create',
diff --git a/api/gen_sdk/chromite/api/metadata_pb2.py b/api/gen_sdk/chromite/api/metadata_pb2.py
new file mode 100644
index 0000000..0977904
--- /dev/null
+++ b/api/gen_sdk/chromite/api/metadata_pb2.py
@@ -0,0 +1,147 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: chromite/api/metadata.proto
+
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from chromite.api.gen_sdk.chromite.api import build_api_pb2 as chromite_dot_api_dot_build__api__pb2
+from chromite.api.gen_sdk.chromite.api import sysroot_pb2 as chromite_dot_api_dot_sysroot__pb2
+from chromite.api.gen_sdk.chromiumos import common_pb2 as chromiumos_dot_common__pb2
+from chromite.api.gen_sdk.chromiumos.build.api import system_image_pb2 as chromiumos_dot_build_dot_api_dot_system__image__pb2
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='chromite/api/metadata.proto',
+  package='chromite.api',
+  syntax='proto3',
+  serialized_options=b'Z6go.chromium.org/chromiumos/infra/proto/go/chromite/api',
+  serialized_pb=b'\n\x1b\x63hromite/api/metadata.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x1a\x63hromite/api/sysroot.proto\x1a\x17\x63hromiumos/common.proto\x1a\'chromiumos/build/api/system_image.proto\"h\n\x1aSystemImageMetadataRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\"V\n\x1bSystemImageMetadataResponse\x12\x37\n\x0csystem_image\x18\x01 \x01(\x0b\x32!.chromiumos.build.api.SystemImage2\x8f\x01\n\x0fMetadataService\x12j\n\x13SystemImageMetadata\x12(.chromite.api.SystemImageMetadataRequest\x1a).chromite.api.SystemImageMetadataResponse\x1a\x10\xc2\xed\x1a\x0c\n\x08metadata\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
+  ,
+  dependencies=[chromite_dot_api_dot_build__api__pb2.DESCRIPTOR,chromite_dot_api_dot_sysroot__pb2.DESCRIPTOR,chromiumos_dot_common__pb2.DESCRIPTOR,chromiumos_dot_build_dot_api_dot_system__image__pb2.DESCRIPTOR,])
+
+
+
+
+_SYSTEMIMAGEMETADATAREQUEST = _descriptor.Descriptor(
+  name='SystemImageMetadataRequest',
+  full_name='chromite.api.SystemImageMetadataRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='chroot', full_name='chromite.api.SystemImageMetadataRequest.chroot', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='sysroot', full_name='chromite.api.SystemImageMetadataRequest.sysroot', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=169,
+  serialized_end=273,
+)
+
+
+_SYSTEMIMAGEMETADATARESPONSE = _descriptor.Descriptor(
+  name='SystemImageMetadataResponse',
+  full_name='chromite.api.SystemImageMetadataResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='system_image', full_name='chromite.api.SystemImageMetadataResponse.system_image', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=275,
+  serialized_end=361,
+)
+
+_SYSTEMIMAGEMETADATAREQUEST.fields_by_name['chroot'].message_type = chromiumos_dot_common__pb2._CHROOT
+_SYSTEMIMAGEMETADATAREQUEST.fields_by_name['sysroot'].message_type = chromite_dot_api_dot_sysroot__pb2._SYSROOT
+_SYSTEMIMAGEMETADATARESPONSE.fields_by_name['system_image'].message_type = chromiumos_dot_build_dot_api_dot_system__image__pb2._SYSTEMIMAGE
+DESCRIPTOR.message_types_by_name['SystemImageMetadataRequest'] = _SYSTEMIMAGEMETADATAREQUEST
+DESCRIPTOR.message_types_by_name['SystemImageMetadataResponse'] = _SYSTEMIMAGEMETADATARESPONSE
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+SystemImageMetadataRequest = _reflection.GeneratedProtocolMessageType('SystemImageMetadataRequest', (_message.Message,), {
+  'DESCRIPTOR' : _SYSTEMIMAGEMETADATAREQUEST,
+  '__module__' : 'chromite.api.metadata_pb2'
+  # @@protoc_insertion_point(class_scope:chromite.api.SystemImageMetadataRequest)
+  })
+_sym_db.RegisterMessage(SystemImageMetadataRequest)
+
+SystemImageMetadataResponse = _reflection.GeneratedProtocolMessageType('SystemImageMetadataResponse', (_message.Message,), {
+  'DESCRIPTOR' : _SYSTEMIMAGEMETADATARESPONSE,
+  '__module__' : 'chromite.api.metadata_pb2'
+  # @@protoc_insertion_point(class_scope:chromite.api.SystemImageMetadataResponse)
+  })
+_sym_db.RegisterMessage(SystemImageMetadataResponse)
+
+
+DESCRIPTOR._options = None
+
+_METADATASERVICE = _descriptor.ServiceDescriptor(
+  name='MetadataService',
+  full_name='chromite.api.MetadataService',
+  file=DESCRIPTOR,
+  index=0,
+  serialized_options=b'\302\355\032\014\n\010metadata\020\001',
+  serialized_start=364,
+  serialized_end=507,
+  methods=[
+  _descriptor.MethodDescriptor(
+    name='SystemImageMetadata',
+    full_name='chromite.api.MetadataService.SystemImageMetadata',
+    index=0,
+    containing_service=None,
+    input_type=_SYSTEMIMAGEMETADATAREQUEST,
+    output_type=_SYSTEMIMAGEMETADATARESPONSE,
+    serialized_options=None,
+  ),
+])
+_sym_db.RegisterServiceDescriptor(_METADATASERVICE)
+
+DESCRIPTOR.services_by_name['MetadataService'] = _METADATASERVICE
+
+# @@protoc_insertion_point(module_scope)
diff --git a/api/gen_sdk/chromite/api/packages_pb2.py b/api/gen_sdk/chromite/api/packages_pb2.py
index 2fe0cb4..6013fea 100644
--- a/api/gen_sdk/chromite/api/packages_pb2.py
+++ b/api/gen_sdk/chromite/api/packages_pb2.py
@@ -22,7 +22,7 @@
   package='chromite.api',
   syntax='proto3',
   serialized_options=b'Z6go.chromium.org/chromiumos/infra/proto/go/chromite/api',
-  serialized_pb=b'\n\x1b\x63hromite/api/packages.proto\x12\x0c\x63hromite.api\x1a\x1a\x63hromite/api/binhost.proto\x1a\x1c\x63hromite/api/build_api.proto\x1a\x1a\x63hromite/api/sysroot.proto\x1a\x17\x63hromiumos/common.proto\"\x93\x01\n\x13\x42uildsChromeRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12)\n\x08packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\"-\n\x14\x42uildsChromeResponse\x12\x15\n\rbuilds_chrome\x18\x01 \x01(\x08\"n\n\x19GetAndroidMetadataRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\"f\n\x1aGetAndroidMetadataResponse\x12\x17\n\x0f\x61ndroid_package\x18\x01 \x01(\t\x12\x16\n\x0e\x61ndroid_branch\x18\x02 \x01(\t\x12\x17\n\x0f\x61ndroid_version\x18\x03 \x01(\t\"x\n\x15GetBestVisibleRequest\x12\x0c\n\x04\x61tom\x18\x01 \x01(\t\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x03 \x01(\x0b\x32\x17.chromiumos.BuildTarget\"G\n\x16GetBestVisibleResponse\x12-\n\x0cpackage_info\x18\x01 \x01(\x0b\x32\x17.chromiumos.PackageInfo\"l\n\x17GetChromeVersionRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\"+\n\x18GetChromeVersionResponse\x12\x0f\n\x07version\x18\x01 \x01(\t\"\x98\x01\n\x18GetTargetVersionsRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12)\n\x08packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\"\xd7\x01\n\x19GetTargetVersionsResponse\x12\x17\n\x0f\x61ndroid_version\x18\x01 \x01(\t\x12\x1e\n\x16\x61ndroid_branch_version\x18\x02 \x01(\t\x12\x1e\n\x16\x61ndroid_target_version\x18\x03 \x01(\t\x12\x16\n\x0e\x63hrome_version\x18\x04 \x01(\t\x12\x14\n\x0c\x66ull_version\x18\x05 \x01(\t\x12\x19\n\x11milestone_version\x18\x06 \x01(\t\x12\x18\n\x10platform_version\x18\x07 \x01(\t\"n\n\x19GetBuilderMetadataRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\"\x8a\x05\n\x1aGetBuilderMetadataResponse\x12[\n\x15\x62uild_target_metadata\x18\x01 \x03(\x0b\x32<.chromite.api.GetBuilderMetadataResponse.BuildTargetMetadata\x12N\n\x0emodel_metadata\x18\x02 \x03(\x0b\x32\x36.chromite.api.GetBuilderMetadataResponse.ModelMetadata\x1a\xaa\x01\n\rModelMetadata\x12\x12\n\nmodel_name\x18\x01 \x01(\t\x12\x1b\n\x13\x65\x63_firmware_version\x18\x02 \x01(\t\x12\x17\n\x0f\x66irmware_key_id\x18\x03 \x01(\t\x12&\n\x1emain_readonly_firmware_version\x18\x04 \x01(\t\x12\'\n\x1fmain_readwrite_firmware_version\x18\x05 \x01(\t\x1a\x91\x02\n\x13\x42uildTargetMetadata\x12\x14\n\x0c\x62uild_target\x18\x01 \x01(\t\x12 \n\x18\x61ndroid_container_branch\x18\x02 \x01(\t\x12 \n\x18\x61ndroid_container_target\x18\x03 \x01(\t\x12!\n\x19\x61ndroid_container_version\x18\x04 \x01(\t\x12\x13\n\x0b\x61rc_use_set\x18\x05 \x01(\x08\x12\x1b\n\x13\x65\x63_firmware_version\x18\x06 \x01(\t\x12\x14\n\x0c\x66ingerprints\x18\x07 \x03(\t\x12\x16\n\x0ekernel_version\x18\x08 \x01(\t\x12\x1d\n\x15main_firmware_version\x18\t \x01(\t\"}\n\x18HasChromePrebuiltRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x0e\n\x06\x63hrome\x18\x03 \x01(\x08\"1\n\x19HasChromePrebuiltResponse\x12\x14\n\x0chas_prebuilt\x18\x01 \x01(\x08\"}\n\x18NeedsChromeSourceRequest\x12=\n\x0finstall_request\x18\x01 \x01(\x0b\x32$.chromite.api.InstallPackagesRequest\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\"\xa9\x02\n\x19NeedsChromeSourceResponse\x12\x1b\n\x13needs_chrome_source\x18\x01 \x01(\x08\x12?\n\x07reasons\x18\x02 \x03(\x0e\x32..chromite.api.NeedsChromeSourceResponse.Reason\x12)\n\x08packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\x15\n\rbuilds_chrome\x18\x04 \x01(\x08\"l\n\x06Reason\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x0f\n\x0bNO_PREBUILT\x10\x01\x12\x12\n\x0e\x43OMPILE_SOURCE\x10\x02\x12\x0f\n\x0bLOCAL_UPREV\x10\x03\x12\x1b\n\x17\x46OLLOWER_LACKS_PREBUILT\x10\x04\"\xa6\x01\n\x12HasPrebuiltRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x0e\n\x06\x63hrome\x18\x03 \x01(\x08\x12-\n\x0cpackage_info\x18\x04 \x01(\x0b\x32\x17.chromiumos.PackageInfo\"+\n\x13HasPrebuiltResponse\x12\x14\n\x0chas_prebuilt\x18\x01 \x01(\x08\"\xaf\x01\n\x14UprevPackagesRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12.\n\rbuild_targets\x18\x02 \x03(\x0b\x32\x17.chromiumos.BuildTarget\x12/\n\x0coverlay_type\x18\x03 \x01(\x0e\x32\x19.chromite.api.OverlayType\x12\x12\n\noutput_dir\x18\x04 \x01(\t\"\xa3\x02\n\x1cUprevVersionedPackageRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0cpackage_info\x18\x02 \x01(\x0b\x32\x17.chromiumos.PackageInfo\x12\x43\n\x08versions\x18\x03 \x03(\x0b\x32\x31.chromite.api.UprevVersionedPackageRequest.GitRef\x12.\n\rbuild_targets\x18\x04 \x03(\x0b\x32\x17.chromiumos.BuildTarget\x1a;\n\x06GitRef\x12\x12\n\nrepository\x18\x01 \x01(\t\x12\x0b\n\x03ref\x18\x02 \x01(\t\x12\x10\n\x08revision\x18\x03 \x01(\t\"\xb1\x01\n\x15UprevPackagesResponse\x12\x44\n\x10modified_ebuilds\x18\x01 \x03(\x0b\x32*.chromite.api.UprevPackagesResponse.Ebuild\x12\x0f\n\x07version\x18\x02 \x01(\t\x12)\n\x08packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x1a\x16\n\x06\x45\x62uild\x12\x0c\n\x04path\x18\x01 \x01(\t\"W\n\x1dUprevVersionedPackageResponse\x12\x36\n\tresponses\x18\x01 \x03(\x0b\x32#.chromite.api.UprevPackagesResponse2\xe5\x08\n\x0ePackageService\x12U\n\x0c\x42uildsChrome\x12!.chromite.api.BuildsChromeRequest\x1a\".chromite.api.BuildsChromeResponse\x12g\n\x12GetAndroidMetadata\x12\'.chromite.api.GetAndroidMetadataRequest\x1a(.chromite.api.GetAndroidMetadataResponse\x12[\n\x0eGetBestVisible\x12#.chromite.api.GetBestVisibleRequest\x1a$.chromite.api.GetBestVisibleResponse\x12\x61\n\x10GetChromeVersion\x12%.chromite.api.GetChromeVersionRequest\x1a&.chromite.api.GetChromeVersionResponse\x12\x64\n\x11GetTargetVersions\x12&.chromite.api.GetTargetVersionsRequest\x1a\'.chromite.api.GetTargetVersionsResponse\x12g\n\x12GetBuilderMetadata\x12\'.chromite.api.GetBuilderMetadataRequest\x1a(.chromite.api.GetBuilderMetadataResponse\x12\x64\n\x11HasChromePrebuilt\x12&.chromite.api.HasChromePrebuiltRequest\x1a\'.chromite.api.HasChromePrebuiltResponse\x12R\n\x0bHasPrebuilt\x12 .chromite.api.HasPrebuiltRequest\x1a!.chromite.api.HasPrebuiltResponse\x12\x64\n\x11NeedsChromeSource\x12&.chromite.api.NeedsChromeSourceRequest\x1a\'.chromite.api.NeedsChromeSourceResponse\x12X\n\x05Uprev\x12\".chromite.api.UprevPackagesRequest\x1a#.chromite.api.UprevPackagesResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x12x\n\x15UprevVersionedPackage\x12*.chromite.api.UprevVersionedPackageRequest\x1a+.chromite.api.UprevVersionedPackageResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x1a\x10\xc2\xed\x1a\x0c\n\x08packages\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
+  serialized_pb=b'\n\x1b\x63hromite/api/packages.proto\x12\x0c\x63hromite.api\x1a\x1a\x63hromite/api/binhost.proto\x1a\x1c\x63hromite/api/build_api.proto\x1a\x1a\x63hromite/api/sysroot.proto\x1a\x17\x63hromiumos/common.proto\"\x93\x01\n\x13\x42uildsChromeRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12)\n\x08packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\"-\n\x14\x42uildsChromeResponse\x12\x15\n\rbuilds_chrome\x18\x01 \x01(\x08\"n\n\x19GetAndroidMetadataRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\"f\n\x1aGetAndroidMetadataResponse\x12\x17\n\x0f\x61ndroid_package\x18\x01 \x01(\t\x12\x16\n\x0e\x61ndroid_branch\x18\x02 \x01(\t\x12\x17\n\x0f\x61ndroid_version\x18\x03 \x01(\t\"x\n\x15GetBestVisibleRequest\x12\x0c\n\x04\x61tom\x18\x01 \x01(\t\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x03 \x01(\x0b\x32\x17.chromiumos.BuildTarget\"G\n\x16GetBestVisibleResponse\x12-\n\x0cpackage_info\x18\x01 \x01(\x0b\x32\x17.chromiumos.PackageInfo\"l\n\x17GetChromeVersionRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\"+\n\x18GetChromeVersionResponse\x12\x0f\n\x07version\x18\x01 \x01(\t\"\x98\x01\n\x18GetTargetVersionsRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12)\n\x08packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\"\xd7\x01\n\x19GetTargetVersionsResponse\x12\x17\n\x0f\x61ndroid_version\x18\x01 \x01(\t\x12\x1e\n\x16\x61ndroid_branch_version\x18\x02 \x01(\t\x12\x1e\n\x16\x61ndroid_target_version\x18\x03 \x01(\t\x12\x16\n\x0e\x63hrome_version\x18\x04 \x01(\t\x12\x14\n\x0c\x66ull_version\x18\x05 \x01(\t\x12\x19\n\x11milestone_version\x18\x06 \x01(\t\x12\x18\n\x10platform_version\x18\x07 \x01(\t\"n\n\x19GetBuilderMetadataRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\"\x8a\x05\n\x1aGetBuilderMetadataResponse\x12[\n\x15\x62uild_target_metadata\x18\x01 \x03(\x0b\x32<.chromite.api.GetBuilderMetadataResponse.BuildTargetMetadata\x12N\n\x0emodel_metadata\x18\x02 \x03(\x0b\x32\x36.chromite.api.GetBuilderMetadataResponse.ModelMetadata\x1a\xaa\x01\n\rModelMetadata\x12\x12\n\nmodel_name\x18\x01 \x01(\t\x12\x1b\n\x13\x65\x63_firmware_version\x18\x02 \x01(\t\x12\x17\n\x0f\x66irmware_key_id\x18\x03 \x01(\t\x12&\n\x1emain_readonly_firmware_version\x18\x04 \x01(\t\x12\'\n\x1fmain_readwrite_firmware_version\x18\x05 \x01(\t\x1a\x91\x02\n\x13\x42uildTargetMetadata\x12\x14\n\x0c\x62uild_target\x18\x01 \x01(\t\x12 \n\x18\x61ndroid_container_branch\x18\x02 \x01(\t\x12 \n\x18\x61ndroid_container_target\x18\x03 \x01(\t\x12!\n\x19\x61ndroid_container_version\x18\x04 \x01(\t\x12\x13\n\x0b\x61rc_use_set\x18\x05 \x01(\x08\x12\x1b\n\x13\x65\x63_firmware_version\x18\x06 \x01(\t\x12\x14\n\x0c\x66ingerprints\x18\x07 \x03(\t\x12\x16\n\x0ekernel_version\x18\x08 \x01(\t\x12\x1d\n\x15main_firmware_version\x18\t \x01(\t\"}\n\x18HasChromePrebuiltRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x0e\n\x06\x63hrome\x18\x03 \x01(\x08\"1\n\x19HasChromePrebuiltResponse\x12\x14\n\x0chas_prebuilt\x18\x01 \x01(\x08\"}\n\x18NeedsChromeSourceRequest\x12=\n\x0finstall_request\x18\x01 \x01(\x0b\x32$.chromite.api.InstallPackagesRequest\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\"\xa9\x02\n\x19NeedsChromeSourceResponse\x12\x1b\n\x13needs_chrome_source\x18\x01 \x01(\x08\x12?\n\x07reasons\x18\x02 \x03(\x0e\x32..chromite.api.NeedsChromeSourceResponse.Reason\x12)\n\x08packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\x15\n\rbuilds_chrome\x18\x04 \x01(\x08\"l\n\x06Reason\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x0f\n\x0bNO_PREBUILT\x10\x01\x12\x12\n\x0e\x43OMPILE_SOURCE\x10\x02\x12\x0f\n\x0bLOCAL_UPREV\x10\x03\x12\x1b\n\x17\x46OLLOWER_LACKS_PREBUILT\x10\x04\"\xa6\x01\n\x12HasPrebuiltRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x0e\n\x06\x63hrome\x18\x03 \x01(\x08\x12-\n\x0cpackage_info\x18\x04 \x01(\x0b\x32\x17.chromiumos.PackageInfo\"+\n\x13HasPrebuiltResponse\x12\x14\n\x0chas_prebuilt\x18\x01 \x01(\x08\"\xaf\x01\n\x14UprevPackagesRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12.\n\rbuild_targets\x18\x02 \x03(\x0b\x32\x17.chromiumos.BuildTarget\x12/\n\x0coverlay_type\x18\x03 \x01(\x0e\x32\x19.chromite.api.OverlayType\x12\x12\n\noutput_dir\x18\x04 \x01(\t\"\xa3\x02\n\x1cUprevVersionedPackageRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12-\n\x0cpackage_info\x18\x02 \x01(\x0b\x32\x17.chromiumos.PackageInfo\x12\x43\n\x08versions\x18\x03 \x03(\x0b\x32\x31.chromite.api.UprevVersionedPackageRequest.GitRef\x12.\n\rbuild_targets\x18\x04 \x03(\x0b\x32\x17.chromiumos.BuildTarget\x1a;\n\x06GitRef\x12\x12\n\nrepository\x18\x01 \x01(\t\x12\x0b\n\x03ref\x18\x02 \x01(\t\x12\x10\n\x08revision\x18\x03 \x01(\t\"\xd1\x01\n\x15UprevPackagesResponse\x12\x44\n\x10modified_ebuilds\x18\x01 \x03(\x0b\x32*.chromite.api.UprevPackagesResponse.Ebuild\x12\x0f\n\x07version\x18\x02 \x01(\t\x12)\n\x08packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\x1e\n\x16\x61\x64\x64itional_commit_info\x18\x04 \x01(\t\x1a\x16\n\x06\x45\x62uild\x12\x0c\n\x04path\x18\x01 \x01(\t\"W\n\x1dUprevVersionedPackageResponse\x12\x36\n\tresponses\x18\x01 \x03(\x0b\x32#.chromite.api.UprevPackagesResponse\"\x16\n\x14RevBumpChromeRequest2\xcf\t\n\x0ePackageService\x12U\n\x0c\x42uildsChrome\x12!.chromite.api.BuildsChromeRequest\x1a\".chromite.api.BuildsChromeResponse\x12g\n\x12GetAndroidMetadata\x12\'.chromite.api.GetAndroidMetadataRequest\x1a(.chromite.api.GetAndroidMetadataResponse\x12[\n\x0eGetBestVisible\x12#.chromite.api.GetBestVisibleRequest\x1a$.chromite.api.GetBestVisibleResponse\x12\x61\n\x10GetChromeVersion\x12%.chromite.api.GetChromeVersionRequest\x1a&.chromite.api.GetChromeVersionResponse\x12\x64\n\x11GetTargetVersions\x12&.chromite.api.GetTargetVersionsRequest\x1a\'.chromite.api.GetTargetVersionsResponse\x12g\n\x12GetBuilderMetadata\x12\'.chromite.api.GetBuilderMetadataRequest\x1a(.chromite.api.GetBuilderMetadataResponse\x12\x64\n\x11HasChromePrebuilt\x12&.chromite.api.HasChromePrebuiltRequest\x1a\'.chromite.api.HasChromePrebuiltResponse\x12R\n\x0bHasPrebuilt\x12 .chromite.api.HasPrebuiltRequest\x1a!.chromite.api.HasPrebuiltResponse\x12\x64\n\x11NeedsChromeSource\x12&.chromite.api.NeedsChromeSourceRequest\x1a\'.chromite.api.NeedsChromeSourceResponse\x12h\n\rRevBumpChrome\x12\".chromite.api.RevBumpChromeRequest\x1a+.chromite.api.UprevVersionedPackageResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x12X\n\x05Uprev\x12\".chromite.api.UprevPackagesRequest\x1a#.chromite.api.UprevPackagesResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x12x\n\x15UprevVersionedPackage\x12*.chromite.api.UprevVersionedPackageRequest\x1a+.chromite.api.UprevVersionedPackageResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x1a\x10\xc2\xed\x1a\x0c\n\x08packages\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
   ,
   dependencies=[chromite_dot_api_dot_binhost__pb2.DESCRIPTOR,chromite_dot_api_dot_build__api__pb2.DESCRIPTOR,chromite_dot_api_dot_sysroot__pb2.DESCRIPTOR,chromiumos_dot_common__pb2.DESCRIPTOR,])
 
@@ -1129,8 +1129,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3504,
-  serialized_end=3526,
+  serialized_start=3536,
+  serialized_end=3558,
 )
 
 _UPREVPACKAGESRESPONSE = _descriptor.Descriptor(
@@ -1161,6 +1161,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='additional_commit_info', full_name='chromite.api.UprevPackagesResponse.additional_commit_info', index=3,
+      number=4, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -1174,7 +1181,7 @@
   oneofs=[
   ],
   serialized_start=3349,
-  serialized_end=3526,
+  serialized_end=3558,
 )
 
 
@@ -1204,8 +1211,32 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3528,
-  serialized_end=3615,
+  serialized_start=3560,
+  serialized_end=3647,
+)
+
+
+_REVBUMPCHROMEREQUEST = _descriptor.Descriptor(
+  name='RevBumpChromeRequest',
+  full_name='chromite.api.RevBumpChromeRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=3649,
+  serialized_end=3671,
 )
 
 _BUILDSCHROMEREQUEST.fields_by_name['chroot'].message_type = chromiumos_dot_common__pb2._CHROOT
@@ -1271,6 +1302,7 @@
 DESCRIPTOR.message_types_by_name['UprevVersionedPackageRequest'] = _UPREVVERSIONEDPACKAGEREQUEST
 DESCRIPTOR.message_types_by_name['UprevPackagesResponse'] = _UPREVPACKAGESRESPONSE
 DESCRIPTOR.message_types_by_name['UprevVersionedPackageResponse'] = _UPREVVERSIONEDPACKAGERESPONSE
+DESCRIPTOR.message_types_by_name['RevBumpChromeRequest'] = _REVBUMPCHROMEREQUEST
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
 BuildsChromeRequest = _reflection.GeneratedProtocolMessageType('BuildsChromeRequest', (_message.Message,), {
@@ -1459,6 +1491,13 @@
   })
 _sym_db.RegisterMessage(UprevVersionedPackageResponse)
 
+RevBumpChromeRequest = _reflection.GeneratedProtocolMessageType('RevBumpChromeRequest', (_message.Message,), {
+  'DESCRIPTOR' : _REVBUMPCHROMEREQUEST,
+  '__module__' : 'chromite.api.packages_pb2'
+  # @@protoc_insertion_point(class_scope:chromite.api.RevBumpChromeRequest)
+  })
+_sym_db.RegisterMessage(RevBumpChromeRequest)
+
 
 DESCRIPTOR._options = None
 
@@ -1468,8 +1507,8 @@
   file=DESCRIPTOR,
   index=0,
   serialized_options=b'\302\355\032\014\n\010packages\020\001',
-  serialized_start=3618,
-  serialized_end=4743,
+  serialized_start=3674,
+  serialized_end=4905,
   methods=[
   _descriptor.MethodDescriptor(
     name='BuildsChrome',
@@ -1553,9 +1592,18 @@
     serialized_options=None,
   ),
   _descriptor.MethodDescriptor(
+    name='RevBumpChrome',
+    full_name='chromite.api.PackageService.RevBumpChrome',
+    index=9,
+    containing_service=None,
+    input_type=_REVBUMPCHROMEREQUEST,
+    output_type=_UPREVVERSIONEDPACKAGERESPONSE,
+    serialized_options=b'\302\355\032\002\020\002',
+  ),
+  _descriptor.MethodDescriptor(
     name='Uprev',
     full_name='chromite.api.PackageService.Uprev',
-    index=9,
+    index=10,
     containing_service=None,
     input_type=_UPREVPACKAGESREQUEST,
     output_type=_UPREVPACKAGESRESPONSE,
@@ -1564,7 +1612,7 @@
   _descriptor.MethodDescriptor(
     name='UprevVersionedPackage',
     full_name='chromite.api.PackageService.UprevVersionedPackage',
-    index=10,
+    index=11,
     containing_service=None,
     input_type=_UPREVVERSIONEDPACKAGEREQUEST,
     output_type=_UPREVVERSIONEDPACKAGERESPONSE,
diff --git a/api/gen_sdk/chromite/api/payload_pb2.py b/api/gen_sdk/chromite/api/payload_pb2.py
index d3d2d15..c015c7b 100644
--- a/api/gen_sdk/chromite/api/payload_pb2.py
+++ b/api/gen_sdk/chromite/api/payload_pb2.py
@@ -20,12 +20,34 @@
   package='chromite.api',
   syntax='proto3',
   serialized_options=b'Z6go.chromium.org/chromiumos/infra/proto/go/chromite/api',
-  serialized_pb=b'\n\x1a\x63hromite/api/payload.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x17\x63hromiumos/common.proto\"h\n\x05\x42uild\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x0f\n\x07version\x18\x02 \x01(\t\x12\x0e\n\x06\x62ucket\x18\x03 \x01(\t\x12\x0f\n\x07\x63hannel\x18\x04 \x01(\t\"\x91\x01\n\x08\x44LCImage\x12\"\n\x05\x62uild\x18\x01 \x01(\x0b\x32\x13.chromite.api.Build\x12\x0e\n\x06\x64lc_id\x18\x02 \x01(\t\x12\x13\n\x0b\x64lc_package\x18\x03 \x01(\t\x12\x11\n\tdlc_image\x18\x04 \x01(\t\x12)\n\nimage_type\x18\x05 \x01(\x0e\x32\x15.chromiumos.ImageType\"i\n\x0bSignedImage\x12\"\n\x05\x62uild\x18\x01 \x01(\x0b\x32\x13.chromite.api.Build\x12)\n\nimage_type\x18\x02 \x01(\x0e\x32\x15.chromiumos.ImageType\x12\x0b\n\x03key\x18\x03 \x01(\t\"q\n\rUnsignedImage\x12\"\n\x05\x62uild\x18\x01 \x01(\x0b\x32\x13.chromite.api.Build\x12)\n\nimage_type\x18\x02 \x01(\x0e\x32\x15.chromiumos.ImageType\x12\x11\n\tmilestone\x18\x03 \x01(\t\"\xfa\x03\n\x11GenerationRequest\x12\x15\n\x0b\x66ull_update\x18\x01 \x01(\x08H\x00\x12\x35\n\x10src_signed_image\x18\x02 \x01(\x0b\x32\x19.chromite.api.SignedImageH\x00\x12\x39\n\x12src_unsigned_image\x18\x03 \x01(\x0b\x32\x1b.chromite.api.UnsignedImageH\x00\x12/\n\rsrc_dlc_image\x18\n \x01(\x0b\x32\x16.chromite.api.DLCImageH\x00\x12\x35\n\x10tgt_signed_image\x18\x04 \x01(\x0b\x32\x19.chromite.api.SignedImageH\x01\x12\x39\n\x12tgt_unsigned_image\x18\x05 \x01(\x0b\x32\x1b.chromite.api.UnsignedImageH\x01\x12/\n\rtgt_dlc_image\x18\x0b \x01(\x0b\x32\x16.chromite.api.DLCImageH\x01\x12\x0e\n\x06\x62ucket\x18\x06 \x01(\t\x12\x0e\n\x06verify\x18\x07 \x01(\x08\x12\x0e\n\x06keyset\x18\x08 \x01(\t\x12\x0e\n\x06\x64ryrun\x18\t \x01(\x08\x12\"\n\x06\x63hroot\x18\x0c \x01(\x0b\x32\x12.chromiumos.ChrootB\x11\n\x0fsrc_image_oneofB\x11\n\x0ftgt_image_oneof\"M\n\x12GenerationResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x12\n\nlocal_path\x18\x02 \x01(\t\x12\x12\n\nremote_uri\x18\x03 \x01(\t2w\n\x0ePayloadService\x12T\n\x0fGeneratePayload\x12\x1f.chromite.api.GenerationRequest\x1a .chromite.api.GenerationResponse\x1a\x0f\xc2\xed\x1a\x0b\n\x07payload\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
+  serialized_pb=b'\n\x1a\x63hromite/api/payload.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x17\x63hromiumos/common.proto\"h\n\x05\x42uild\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x0f\n\x07version\x18\x02 \x01(\t\x12\x0e\n\x06\x62ucket\x18\x03 \x01(\t\x12\x0f\n\x07\x63hannel\x18\x04 \x01(\t\"\x91\x01\n\x08\x44LCImage\x12\"\n\x05\x62uild\x18\x01 \x01(\x0b\x32\x13.chromite.api.Build\x12\x0e\n\x06\x64lc_id\x18\x02 \x01(\t\x12\x13\n\x0b\x64lc_package\x18\x03 \x01(\t\x12\x11\n\tdlc_image\x18\x04 \x01(\t\x12)\n\nimage_type\x18\x05 \x01(\x0e\x32\x15.chromiumos.ImageType\"i\n\x0bSignedImage\x12\"\n\x05\x62uild\x18\x01 \x01(\x0b\x32\x13.chromite.api.Build\x12)\n\nimage_type\x18\x02 \x01(\x0e\x32\x15.chromiumos.ImageType\x12\x0b\n\x03key\x18\x03 \x01(\t\"q\n\rUnsignedImage\x12\"\n\x05\x62uild\x18\x01 \x01(\x0b\x32\x13.chromite.api.Build\x12)\n\nimage_type\x18\x02 \x01(\x0e\x32\x15.chromiumos.ImageType\x12\x11\n\tmilestone\x18\x03 \x01(\t\"\x8a\x04\n\x11GenerationRequest\x12\x15\n\x0b\x66ull_update\x18\x01 \x01(\x08H\x00\x12\x35\n\x10src_signed_image\x18\x02 \x01(\x0b\x32\x19.chromite.api.SignedImageH\x00\x12\x39\n\x12src_unsigned_image\x18\x03 \x01(\x0b\x32\x1b.chromite.api.UnsignedImageH\x00\x12/\n\rsrc_dlc_image\x18\n \x01(\x0b\x32\x16.chromite.api.DLCImageH\x00\x12\x35\n\x10tgt_signed_image\x18\x04 \x01(\x0b\x32\x19.chromite.api.SignedImageH\x01\x12\x39\n\x12tgt_unsigned_image\x18\x05 \x01(\x0b\x32\x1b.chromite.api.UnsignedImageH\x01\x12/\n\rtgt_dlc_image\x18\x0b \x01(\x0b\x32\x16.chromite.api.DLCImageH\x01\x12\x0e\n\x06\x62ucket\x18\x06 \x01(\t\x12\x0e\n\x06verify\x18\x07 \x01(\x08\x12\x0e\n\x06keyset\x18\x08 \x01(\t\x12\x0e\n\x06\x64ryrun\x18\t \x01(\x08\x12\"\n\x06\x63hroot\x18\x0c \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x0e\n\x06minios\x18\r \x01(\x08\x42\x11\n\x0fsrc_image_oneofB\x11\n\x0ftgt_image_oneof\"\xd2\x01\n\x12GenerationResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x12\n\nlocal_path\x18\x02 \x01(\t\x12\x12\n\nremote_uri\x18\x03 \x01(\t\x12\x46\n\x0e\x66\x61ilure_reason\x18\x04 \x01(\x0e\x32..chromite.api.GenerationResponse.FailureReason\";\n\rFailureReason\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x19\n\x15NOT_MINIOS_COMPATIBLE\x10\x01\x32w\n\x0ePayloadService\x12T\n\x0fGeneratePayload\x12\x1f.chromite.api.GenerationRequest\x1a .chromite.api.GenerationResponse\x1a\x0f\xc2\xed\x1a\x0b\n\x07payload\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
   ,
   dependencies=[chromite_dot_api_dot_build__api__pb2.DESCRIPTOR,chromiumos_dot_common__pb2.DESCRIPTOR,])
 
 
 
+_GENERATIONRESPONSE_FAILUREREASON = _descriptor.EnumDescriptor(
+  name='FailureReason',
+  full_name='chromite.api.GenerationResponse.FailureReason',
+  filename=None,
+  file=DESCRIPTOR,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='UNSPECIFIED', index=0, number=0,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='NOT_MINIOS_COMPATIBLE', index=1, number=1,
+      serialized_options=None,
+      type=None),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=1252,
+  serialized_end=1311,
+)
+_sym_db.RegisterEnumDescriptor(_GENERATIONRESPONSE_FAILUREREASON)
+
 
 _BUILD = _descriptor.Descriptor(
   name='Build',
@@ -319,6 +341,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='minios', full_name='chromite.api.GenerationRequest.minios', index=12,
+      number=13, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -338,7 +367,7 @@
       index=1, containing_type=None, fields=[]),
   ],
   serialized_start=576,
-  serialized_end=1082,
+  serialized_end=1098,
 )
 
 
@@ -370,11 +399,19 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='failure_reason', full_name='chromite.api.GenerationResponse.failure_reason', index=3,
+      number=4, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
   nested_types=[],
   enum_types=[
+    _GENERATIONRESPONSE_FAILUREREASON,
   ],
   serialized_options=None,
   is_extendable=False,
@@ -382,8 +419,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1084,
-  serialized_end=1161,
+  serialized_start=1101,
+  serialized_end=1311,
 )
 
 _BUILD.fields_by_name['build_target'].message_type = chromiumos_dot_common__pb2._BUILDTARGET
@@ -421,6 +458,8 @@
 _GENERATIONREQUEST.oneofs_by_name['tgt_image_oneof'].fields.append(
   _GENERATIONREQUEST.fields_by_name['tgt_dlc_image'])
 _GENERATIONREQUEST.fields_by_name['tgt_dlc_image'].containing_oneof = _GENERATIONREQUEST.oneofs_by_name['tgt_image_oneof']
+_GENERATIONRESPONSE.fields_by_name['failure_reason'].enum_type = _GENERATIONRESPONSE_FAILUREREASON
+_GENERATIONRESPONSE_FAILUREREASON.containing_type = _GENERATIONRESPONSE
 DESCRIPTOR.message_types_by_name['Build'] = _BUILD
 DESCRIPTOR.message_types_by_name['DLCImage'] = _DLCIMAGE
 DESCRIPTOR.message_types_by_name['SignedImage'] = _SIGNEDIMAGE
@@ -480,8 +519,8 @@
   file=DESCRIPTOR,
   index=0,
   serialized_options=b'\302\355\032\013\n\007payload\020\001',
-  serialized_start=1163,
-  serialized_end=1282,
+  serialized_start=1313,
+  serialized_end=1432,
   methods=[
   _descriptor.MethodDescriptor(
     name='GeneratePayload',
diff --git a/api/gen_sdk/chromite/api/sdk_pb2.py b/api/gen_sdk/chromite/api/sdk_pb2.py
index 14f563f..7b7216d 100644
--- a/api/gen_sdk/chromite/api/sdk_pb2.py
+++ b/api/gen_sdk/chromite/api/sdk_pb2.py
@@ -20,7 +20,7 @@
   package='chromite.api',
   syntax='proto3',
   serialized_options=b'Z6go.chromium.org/chromiumos/infra/proto/go/chromite/api',
-  serialized_pb=b'\n\x16\x63hromite/api/sdk.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x17\x63hromiumos/common.proto\" \n\rChrootVersion\x12\x0f\n\x07version\x18\x01 \x01(\r\"\xab\x01\n\rCreateRequest\x12\x30\n\x05\x66lags\x18\x01 \x01(\x0b\x32!.chromite.api.CreateRequest.Flags\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x1a\x44\n\x05\x46lags\x12\x12\n\nno_replace\x18\x01 \x01(\x08\x12\x11\n\tbootstrap\x18\x02 \x01(\x08\x12\x14\n\x0cno_use_image\x18\x03 \x01(\x08\">\n\x0e\x43reateResponse\x12,\n\x07version\x18\x01 \x01(\x0b\x32\x1b.chromite.api.ChrootVersion\"3\n\rDeleteRequest\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x10\n\x0e\x44\x65leteResponse\"4\n\x0eUnmountRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x11\n\x0fUnmountResponse\"\xd3\x01\n\rUpdateRequest\x12\x30\n\x05\x66lags\x18\x01 \x01(\x0b\x32!.chromite.api.UpdateRequest.Flags\x12\x32\n\x11toolchain_targets\x18\x02 \x03(\x0b\x32\x17.chromiumos.BuildTarget\x12\"\n\x06\x63hroot\x18\x03 \x01(\x0b\x32\x12.chromiumos.Chroot\x1a\x38\n\x05\x46lags\x12\x14\n\x0c\x62uild_source\x18\x01 \x01(\x08\x12\x19\n\x11toolchain_changed\x18\x02 \x01(\x08\">\n\x0eUpdateResponse\x12,\n\x07version\x18\x01 \x01(\x0b\x32\x1b.chromite.api.ChrootVersion\"2\n\x0c\x43leanRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x0f\n\rCleanResponse\"\x1e\n\rSnapshotToken\x12\r\n\x05value\x18\x01 \x01(\t\";\n\x15\x43reateSnapshotRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\"M\n\x16\x43reateSnapshotResponse\x12\x33\n\x0esnapshot_token\x18\x01 \x01(\x0b\x32\x1b.chromite.api.SnapshotToken\"q\n\x16RestoreSnapshotRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x33\n\x0esnapshot_token\x18\x02 \x01(\x0b\x32\x1b.chromite.api.SnapshotToken\"\x19\n\x17RestoreSnapshotResponse\"4\n\x12UnmountPathRequest\x12\x1e\n\x04path\x18\x01 \x01(\x0b\x32\x10.chromiumos.Path\"\x15\n\x13UnmountPathResponse2\x8b\x05\n\nSdkService\x12\x43\n\x06\x43reate\x12\x1b.chromite.api.CreateRequest\x1a\x1c.chromite.api.CreateResponse\x12\x43\n\x06\x44\x65lete\x12\x1b.chromite.api.DeleteRequest\x1a\x1c.chromite.api.DeleteResponse\x12@\n\x05\x43lean\x12\x1a.chromite.api.CleanRequest\x1a\x1b.chromite.api.CleanResponse\x12\x46\n\x07Unmount\x12\x1c.chromite.api.UnmountRequest\x1a\x1d.chromite.api.UnmountResponse\x12K\n\x06Update\x12\x1b.chromite.api.UpdateRequest\x1a\x1c.chromite.api.UpdateResponse\"\x06\xc2\xed\x1a\x02\x10\x01\x12[\n\x0e\x43reateSnapshot\x12#.chromite.api.CreateSnapshotRequest\x1a$.chromite.api.CreateSnapshotResponse\x12^\n\x0fRestoreSnapshot\x12$.chromite.api.RestoreSnapshotRequest\x1a%.chromite.api.RestoreSnapshotResponse\x12R\n\x0bUnmountPath\x12 .chromite.api.UnmountPathRequest\x1a!.chromite.api.UnmountPathResponse\x1a\x0b\xc2\xed\x1a\x07\n\x03sdk\x10\x02\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
+  serialized_pb=b'\n\x16\x63hromite/api/sdk.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x17\x63hromiumos/common.proto\" \n\rChrootVersion\x12\x0f\n\x07version\x18\x01 \x01(\r\"\xc0\x01\n\rCreateRequest\x12\x30\n\x05\x66lags\x18\x01 \x01(\x0b\x32!.chromite.api.CreateRequest.Flags\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x13\n\x0bsdk_version\x18\x03 \x01(\t\x1a\x44\n\x05\x46lags\x12\x12\n\nno_replace\x18\x01 \x01(\x08\x12\x11\n\tbootstrap\x18\x02 \x01(\x08\x12\x14\n\x0cno_use_image\x18\x03 \x01(\x08\">\n\x0e\x43reateResponse\x12,\n\x07version\x18\x01 \x01(\x0b\x32\x1b.chromite.api.ChrootVersion\"3\n\rDeleteRequest\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x10\n\x0e\x44\x65leteResponse\"4\n\x0eUnmountRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x11\n\x0fUnmountResponse\"\xd3\x01\n\rUpdateRequest\x12\x30\n\x05\x66lags\x18\x01 \x01(\x0b\x32!.chromite.api.UpdateRequest.Flags\x12\x32\n\x11toolchain_targets\x18\x02 \x03(\x0b\x32\x17.chromiumos.BuildTarget\x12\"\n\x06\x63hroot\x18\x03 \x01(\x0b\x32\x12.chromiumos.Chroot\x1a\x38\n\x05\x46lags\x12\x14\n\x0c\x62uild_source\x18\x01 \x01(\x08\x12\x19\n\x11toolchain_changed\x18\x02 \x01(\x08\">\n\x0eUpdateResponse\x12,\n\x07version\x18\x01 \x01(\x0b\x32\x1b.chromite.api.ChrootVersion\"2\n\x0c\x43leanRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x0f\n\rCleanResponse\"\x1e\n\rSnapshotToken\x12\r\n\x05value\x18\x01 \x01(\t\";\n\x15\x43reateSnapshotRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\"M\n\x16\x43reateSnapshotResponse\x12\x33\n\x0esnapshot_token\x18\x01 \x01(\x0b\x32\x1b.chromite.api.SnapshotToken\"q\n\x16RestoreSnapshotRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x33\n\x0esnapshot_token\x18\x02 \x01(\x0b\x32\x1b.chromite.api.SnapshotToken\"\x19\n\x17RestoreSnapshotResponse\"4\n\x12UnmountPathRequest\x12\x1e\n\x04path\x18\x01 \x01(\x0b\x32\x10.chromiumos.Path\"\x15\n\x13UnmountPathResponse2\x8b\x05\n\nSdkService\x12\x43\n\x06\x43reate\x12\x1b.chromite.api.CreateRequest\x1a\x1c.chromite.api.CreateResponse\x12\x43\n\x06\x44\x65lete\x12\x1b.chromite.api.DeleteRequest\x1a\x1c.chromite.api.DeleteResponse\x12@\n\x05\x43lean\x12\x1a.chromite.api.CleanRequest\x1a\x1b.chromite.api.CleanResponse\x12\x46\n\x07Unmount\x12\x1c.chromite.api.UnmountRequest\x1a\x1d.chromite.api.UnmountResponse\x12K\n\x06Update\x12\x1b.chromite.api.UpdateRequest\x1a\x1c.chromite.api.UpdateResponse\"\x06\xc2\xed\x1a\x02\x10\x01\x12[\n\x0e\x43reateSnapshot\x12#.chromite.api.CreateSnapshotRequest\x1a$.chromite.api.CreateSnapshotResponse\x12^\n\x0fRestoreSnapshot\x12$.chromite.api.RestoreSnapshotRequest\x1a%.chromite.api.RestoreSnapshotResponse\x12R\n\x0bUnmountPath\x12 .chromite.api.UnmountPathRequest\x1a!.chromite.api.UnmountPathResponse\x1a\x0b\xc2\xed\x1a\x07\n\x03sdk\x10\x02\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
   ,
   dependencies=[chromite_dot_api_dot_build__api__pb2.DESCRIPTOR,chromiumos_dot_common__pb2.DESCRIPTOR,])
 
@@ -98,8 +98,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=233,
-  serialized_end=301,
+  serialized_start=254,
+  serialized_end=322,
 )
 
 _CREATEREQUEST = _descriptor.Descriptor(
@@ -123,6 +123,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='sdk_version', full_name='chromite.api.CreateRequest.sdk_version', index=2,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -136,7 +143,7 @@
   oneofs=[
   ],
   serialized_start=130,
-  serialized_end=301,
+  serialized_end=322,
 )
 
 
@@ -166,8 +173,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=303,
-  serialized_end=365,
+  serialized_start=324,
+  serialized_end=386,
 )
 
 
@@ -197,8 +204,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=367,
-  serialized_end=418,
+  serialized_start=388,
+  serialized_end=439,
 )
 
 
@@ -221,8 +228,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=420,
-  serialized_end=436,
+  serialized_start=441,
+  serialized_end=457,
 )
 
 
@@ -252,8 +259,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=438,
-  serialized_end=490,
+  serialized_start=459,
+  serialized_end=511,
 )
 
 
@@ -276,8 +283,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=492,
-  serialized_end=509,
+  serialized_start=513,
+  serialized_end=530,
 )
 
 
@@ -314,8 +321,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=667,
-  serialized_end=723,
+  serialized_start=688,
+  serialized_end=744,
 )
 
 _UPDATEREQUEST = _descriptor.Descriptor(
@@ -358,8 +365,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=512,
-  serialized_end=723,
+  serialized_start=533,
+  serialized_end=744,
 )
 
 
@@ -389,8 +396,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=725,
-  serialized_end=787,
+  serialized_start=746,
+  serialized_end=808,
 )
 
 
@@ -420,8 +427,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=789,
-  serialized_end=839,
+  serialized_start=810,
+  serialized_end=860,
 )
 
 
@@ -444,8 +451,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=841,
-  serialized_end=856,
+  serialized_start=862,
+  serialized_end=877,
 )
 
 
@@ -475,8 +482,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=858,
-  serialized_end=888,
+  serialized_start=879,
+  serialized_end=909,
 )
 
 
@@ -506,8 +513,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=890,
-  serialized_end=949,
+  serialized_start=911,
+  serialized_end=970,
 )
 
 
@@ -537,8 +544,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=951,
-  serialized_end=1028,
+  serialized_start=972,
+  serialized_end=1049,
 )
 
 
@@ -575,8 +582,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1030,
-  serialized_end=1143,
+  serialized_start=1051,
+  serialized_end=1164,
 )
 
 
@@ -599,8 +606,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1145,
-  serialized_end=1170,
+  serialized_start=1166,
+  serialized_end=1191,
 )
 
 
@@ -630,8 +637,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1172,
-  serialized_end=1224,
+  serialized_start=1193,
+  serialized_end=1245,
 )
 
 
@@ -654,8 +661,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1226,
-  serialized_end=1247,
+  serialized_start=1247,
+  serialized_end=1268,
 )
 
 _CREATEREQUEST_FLAGS.containing_type = _CREATEREQUEST
@@ -846,8 +853,8 @@
   file=DESCRIPTOR,
   index=0,
   serialized_options=b'\302\355\032\007\n\003sdk\020\002',
-  serialized_start=1250,
-  serialized_end=1901,
+  serialized_start=1271,
+  serialized_end=1922,
   methods=[
   _descriptor.MethodDescriptor(
     name='Create',
diff --git a/api/gen_sdk/chromite/api/sysroot_pb2.py b/api/gen_sdk/chromite/api/sysroot_pb2.py
index 59279b8..6d477b9 100644
--- a/api/gen_sdk/chromite/api/sysroot_pb2.py
+++ b/api/gen_sdk/chromite/api/sysroot_pb2.py
@@ -21,7 +21,7 @@
   package='chromite.api',
   syntax='proto3',
   serialized_options=b'Z6go.chromium.org/chromiumos/infra/proto/go/chromite/api',
-  serialized_pb=b'\n\x1a\x63hromite/api/sysroot.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x17\x63hromiumos/common.proto\x1a\x18\x63hromiumos/metrics.proto\"F\n\x07Sysroot\x12\x0c\n\x04path\x18\x01 \x01(\t\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\"\x17\n\x07Profile\x12\x0c\n\x04name\x18\x01 \x01(\t\"\xce\x02\n\x14SysrootCreateRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x37\n\x05\x66lags\x18\x02 \x01(\x0b\x32(.chromite.api.SysrootCreateRequest.Flags\x12&\n\x07profile\x18\x03 \x01(\x0b\x32\x15.chromite.api.Profile\x12\"\n\x06\x63hroot\x18\x04 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x35\n\x0fpackage_indexes\x18\x05 \x03(\x0b\x32\x1c.chromiumos.PackageIndexInfo\x1aK\n\x05\x46lags\x12\x16\n\x0e\x63hroot_current\x18\x01 \x01(\x08\x12\x0f\n\x07replace\x18\x02 \x01(\x08\x12\x19\n\x11toolchain_changed\x18\x03 \x01(\x08\"?\n\x15SysrootCreateResponse\x12&\n\x07sysroot\x18\x01 \x01(\x0b\x32\x15.chromite.api.Sysroot\"\xc9\x01\n\x1dSysrootGenerateArchiveRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12)\n\x08packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12*\n\ntarget_dir\x18\x04 \x01(\x0b\x32\x16.chromiumos.ResultPath\"K\n\x1eSysrootGenerateArchiveResponse\x12)\n\x0fsysroot_archive\x18\x01 \x01(\x0b\x32\x10.chromiumos.Path\"\xdd\x01\n\x17InstallToolchainRequest\x12&\n\x07sysroot\x18\x01 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12:\n\x05\x66lags\x18\x02 \x01(\x0b\x32+.chromite.api.InstallToolchainRequest.Flags\x12\"\n\x06\x63hroot\x18\x03 \x01(\x0b\x32\x12.chromiumos.Chroot\x1a:\n\x05\x46lags\x12\x16\n\x0e\x63ompile_source\x18\x01 \x01(\x08\x12\x19\n\x11toolchain_changed\x18\x02 \x01(\x08\"L\n\x18InstallToolchainResponse\x12\x30\n\x0f\x66\x61iled_packages\x18\x01 \x03(\x0b\x32\x17.chromiumos.PackageInfo\"\xc6\x03\n\x16InstallPackagesRequest\x12&\n\x07sysroot\x18\x01 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\x39\n\x05\x66lags\x18\x02 \x01(\x0b\x32*.chromite.api.InstallPackagesRequest.Flags\x12)\n\x08packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\"\n\x06\x63hroot\x18\x04 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\tuse_flags\x18\x05 \x03(\x0b\x32\x13.chromiumos.UseFlag\x12+\n\x0bgoma_config\x18\x06 \x01(\x0b\x32\x16.chromiumos.GomaConfig\x12\x35\n\x0fpackage_indexes\x18\x07 \x03(\x0b\x32\x1c.chromiumos.PackageIndexInfo\x1an\n\x05\x46lags\x12\x16\n\x0e\x63ompile_source\x18\x01 \x01(\x08\x12\x10\n\x08use_goma\x18\x03 \x01(\x08\x12\x19\n\x11toolchain_changed\x18\x04 \x01(\x08\x12\x0e\n\x06\x64ryrun\x18\x05 \x01(\x08J\x04\x08\x02\x10\x03R\nevent_file\"\xa7\x01\n\x17InstallPackagesResponse\x12\x30\n\x0f\x66\x61iled_packages\x18\x01 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\'\n\x06\x65vents\x18\x02 \x03(\x0b\x32\x17.chromiumos.MetricEvent\x12\x31\n\x0egoma_artifacts\x18\x03 \x01(\x0b\x32\x19.chromiumos.GomaArtifacts\"\xb4\x01\n CreateSimpleChromeSysrootRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x11\n\tuse_flags\x18\x02 \x03(\t\x12*\n\ntarget_dir\x18\x03 \x01(\x0b\x32\x16.chromiumos.ResultPath\x12\"\n\x06\x63hroot\x18\x04 \x01(\x0b\x32\x12.chromiumos.Chroot\"N\n!CreateSimpleChromeSysrootResponse\x12)\n\x0fsysroot_archive\x18\x01 \x01(\x0b\x32\x10.chromiumos.Path2\xa3\x04\n\x0eSysrootService\x12Q\n\x06\x43reate\x12\".chromite.api.SysrootCreateRequest\x1a#.chromite.api.SysrootCreateResponse\x12l\n\x0fGenerateArchive\x12+.chromite.api.SysrootGenerateArchiveRequest\x1a,.chromite.api.SysrootGenerateArchiveResponse\x12\x61\n\x10InstallToolchain\x12%.chromite.api.InstallToolchainRequest\x1a&.chromite.api.InstallToolchainResponse\x12^\n\x0fInstallPackages\x12$.chromite.api.InstallPackagesRequest\x1a%.chromite.api.InstallPackagesResponse\x12|\n\x19\x43reateSimpleChromeSysroot\x12..chromite.api.CreateSimpleChromeSysrootRequest\x1a/.chromite.api.CreateSimpleChromeSysrootResponse\x1a\x0f\xc2\xed\x1a\x0b\n\x07sysroot\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
+  serialized_pb=b'\n\x1a\x63hromite/api/sysroot.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x17\x63hromiumos/common.proto\x1a\x18\x63hromiumos/metrics.proto\"F\n\x07Sysroot\x12\x0c\n\x04path\x18\x01 \x01(\t\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\"\x17\n\x07Profile\x12\x0c\n\x04name\x18\x01 \x01(\t\"\xce\x02\n\x14SysrootCreateRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x37\n\x05\x66lags\x18\x02 \x01(\x0b\x32(.chromite.api.SysrootCreateRequest.Flags\x12&\n\x07profile\x18\x03 \x01(\x0b\x32\x15.chromite.api.Profile\x12\"\n\x06\x63hroot\x18\x04 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x35\n\x0fpackage_indexes\x18\x05 \x03(\x0b\x32\x1c.chromiumos.PackageIndexInfo\x1aK\n\x05\x46lags\x12\x16\n\x0e\x63hroot_current\x18\x01 \x01(\x08\x12\x0f\n\x07replace\x18\x02 \x01(\x08\x12\x19\n\x11toolchain_changed\x18\x03 \x01(\x08\"?\n\x15SysrootCreateResponse\x12&\n\x07sysroot\x18\x01 \x01(\x0b\x32\x15.chromite.api.Sysroot\"\xc9\x01\n\x1dSysrootGenerateArchiveRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12)\n\x08packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12*\n\ntarget_dir\x18\x04 \x01(\x0b\x32\x16.chromiumos.ResultPath\"K\n\x1eSysrootGenerateArchiveResponse\x12)\n\x0fsysroot_archive\x18\x01 \x01(\x0b\x32\x10.chromiumos.Path\"\xdd\x01\n\x17InstallToolchainRequest\x12&\n\x07sysroot\x18\x01 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12:\n\x05\x66lags\x18\x02 \x01(\x0b\x32+.chromite.api.InstallToolchainRequest.Flags\x12\"\n\x06\x63hroot\x18\x03 \x01(\x0b\x32\x12.chromiumos.Chroot\x1a:\n\x05\x46lags\x12\x16\n\x0e\x63ompile_source\x18\x01 \x01(\x08\x12\x19\n\x11toolchain_changed\x18\x02 \x01(\x08\"\x8a\x01\n\x18InstallToolchainResponse\x12\x30\n\x0f\x66\x61iled_packages\x18\x01 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12<\n\x13\x66\x61iled_package_data\x18\x04 \x03(\x0b\x32\x1f.chromite.api.FailedPackageData\"\x96\x04\n\x16InstallPackagesRequest\x12&\n\x07sysroot\x18\x01 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\x39\n\x05\x66lags\x18\x02 \x01(\x0b\x32*.chromite.api.InstallPackagesRequest.Flags\x12)\n\x08packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\"\n\x06\x63hroot\x18\x04 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\tuse_flags\x18\x05 \x03(\x0b\x32\x13.chromiumos.UseFlag\x12+\n\x0bgoma_config\x18\x06 \x01(\x0b\x32\x16.chromiumos.GomaConfig\x12\x35\n\x0fpackage_indexes\x18\x07 \x03(\x0b\x32\x1c.chromiumos.PackageIndexInfo\x12\x37\n\x11remoteexec_config\x18\x08 \x01(\x0b\x32\x1c.chromiumos.RemoteexecConfig\x1a\x84\x01\n\x05\x46lags\x12\x16\n\x0e\x63ompile_source\x18\x01 \x01(\x08\x12\x10\n\x08use_goma\x18\x03 \x01(\x08\x12\x19\n\x11toolchain_changed\x18\x04 \x01(\x08\x12\x0e\n\x06\x64ryrun\x18\x05 \x01(\x08J\x04\x08\x02\x10\x03J\x04\x08\x06\x10\x07R\nevent_fileR\x0euse_remoteexec\"\xe5\x01\n\x17InstallPackagesResponse\x12\x30\n\x0f\x66\x61iled_packages\x18\x01 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\'\n\x06\x65vents\x18\x02 \x03(\x0b\x32\x17.chromiumos.MetricEvent\x12\x31\n\x0egoma_artifacts\x18\x03 \x01(\x0b\x32\x19.chromiumos.GomaArtifacts\x12<\n\x13\x66\x61iled_package_data\x18\x04 \x03(\x0b\x32\x1f.chromite.api.FailedPackageData\"^\n\x11\x46\x61iledPackageData\x12%\n\x04name\x18\x01 \x01(\x0b\x32\x17.chromiumos.PackageInfo\x12\"\n\x08log_path\x18\x02 \x01(\x0b\x32\x10.chromiumos.Path\"\xb4\x01\n CreateSimpleChromeSysrootRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x11\n\tuse_flags\x18\x02 \x03(\t\x12*\n\ntarget_dir\x18\x03 \x01(\x0b\x32\x16.chromiumos.ResultPath\x12\"\n\x06\x63hroot\x18\x04 \x01(\x0b\x32\x12.chromiumos.Chroot\"N\n!CreateSimpleChromeSysrootResponse\x12)\n\x0fsysroot_archive\x18\x01 \x01(\x0b\x32\x10.chromiumos.Path2\xa3\x04\n\x0eSysrootService\x12Q\n\x06\x43reate\x12\".chromite.api.SysrootCreateRequest\x1a#.chromite.api.SysrootCreateResponse\x12l\n\x0fGenerateArchive\x12+.chromite.api.SysrootGenerateArchiveRequest\x1a,.chromite.api.SysrootGenerateArchiveResponse\x12\x61\n\x10InstallToolchain\x12%.chromite.api.InstallToolchainRequest\x1a&.chromite.api.InstallToolchainResponse\x12^\n\x0fInstallPackages\x12$.chromite.api.InstallPackagesRequest\x1a%.chromite.api.InstallPackagesResponse\x12|\n\x19\x43reateSimpleChromeSysroot\x12..chromite.api.CreateSimpleChromeSysrootRequest\x1a/.chromite.api.CreateSimpleChromeSysrootResponse\x1a\x0f\xc2\xed\x1a\x0b\n\x07sysroot\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
   ,
   dependencies=[chromite_dot_api_dot_build__api__pb2.DESCRIPTOR,chromiumos_dot_common__pb2.DESCRIPTOR,chromiumos_dot_metrics__pb2.DESCRIPTOR,])
 
@@ -410,6 +410,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='failed_package_data', full_name='chromite.api.InstallToolchainResponse.failed_package_data', index=1,
+      number=4, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -422,8 +429,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1129,
-  serialized_end=1205,
+  serialized_start=1130,
+  serialized_end=1268,
 )
 
 
@@ -474,8 +481,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1552,
-  serialized_end=1662,
+  serialized_start=1673,
+  serialized_end=1805,
 )
 
 _INSTALLPACKAGESREQUEST = _descriptor.Descriptor(
@@ -534,6 +541,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='remoteexec_config', full_name='chromite.api.InstallPackagesRequest.remoteexec_config', index=7,
+      number=8, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -546,8 +560,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1208,
-  serialized_end=1662,
+  serialized_start=1271,
+  serialized_end=1805,
 )
 
 
@@ -579,6 +593,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='failed_package_data', full_name='chromite.api.InstallPackagesResponse.failed_package_data', index=3,
+      number=4, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -591,8 +612,46 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1665,
-  serialized_end=1832,
+  serialized_start=1808,
+  serialized_end=2037,
+)
+
+
+_FAILEDPACKAGEDATA = _descriptor.Descriptor(
+  name='FailedPackageData',
+  full_name='chromite.api.FailedPackageData',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='name', full_name='chromite.api.FailedPackageData.name', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='log_path', full_name='chromite.api.FailedPackageData.log_path', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2039,
+  serialized_end=2133,
 )
 
 
@@ -643,8 +702,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1835,
-  serialized_end=2015,
+  serialized_start=2136,
+  serialized_end=2316,
 )
 
 
@@ -674,8 +733,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2017,
-  serialized_end=2095,
+  serialized_start=2318,
+  serialized_end=2396,
 )
 
 _SYSROOT.fields_by_name['build_target'].message_type = chromiumos_dot_common__pb2._BUILDTARGET
@@ -696,6 +755,7 @@
 _INSTALLTOOLCHAINREQUEST.fields_by_name['flags'].message_type = _INSTALLTOOLCHAINREQUEST_FLAGS
 _INSTALLTOOLCHAINREQUEST.fields_by_name['chroot'].message_type = chromiumos_dot_common__pb2._CHROOT
 _INSTALLTOOLCHAINRESPONSE.fields_by_name['failed_packages'].message_type = chromiumos_dot_common__pb2._PACKAGEINFO
+_INSTALLTOOLCHAINRESPONSE.fields_by_name['failed_package_data'].message_type = _FAILEDPACKAGEDATA
 _INSTALLPACKAGESREQUEST_FLAGS.containing_type = _INSTALLPACKAGESREQUEST
 _INSTALLPACKAGESREQUEST.fields_by_name['sysroot'].message_type = _SYSROOT
 _INSTALLPACKAGESREQUEST.fields_by_name['flags'].message_type = _INSTALLPACKAGESREQUEST_FLAGS
@@ -704,9 +764,13 @@
 _INSTALLPACKAGESREQUEST.fields_by_name['use_flags'].message_type = chromiumos_dot_common__pb2._USEFLAG
 _INSTALLPACKAGESREQUEST.fields_by_name['goma_config'].message_type = chromiumos_dot_common__pb2._GOMACONFIG
 _INSTALLPACKAGESREQUEST.fields_by_name['package_indexes'].message_type = chromiumos_dot_common__pb2._PACKAGEINDEXINFO
+_INSTALLPACKAGESREQUEST.fields_by_name['remoteexec_config'].message_type = chromiumos_dot_common__pb2._REMOTEEXECCONFIG
 _INSTALLPACKAGESRESPONSE.fields_by_name['failed_packages'].message_type = chromiumos_dot_common__pb2._PACKAGEINFO
 _INSTALLPACKAGESRESPONSE.fields_by_name['events'].message_type = chromiumos_dot_metrics__pb2._METRICEVENT
 _INSTALLPACKAGESRESPONSE.fields_by_name['goma_artifacts'].message_type = chromiumos_dot_common__pb2._GOMAARTIFACTS
+_INSTALLPACKAGESRESPONSE.fields_by_name['failed_package_data'].message_type = _FAILEDPACKAGEDATA
+_FAILEDPACKAGEDATA.fields_by_name['name'].message_type = chromiumos_dot_common__pb2._PACKAGEINFO
+_FAILEDPACKAGEDATA.fields_by_name['log_path'].message_type = chromiumos_dot_common__pb2._PATH
 _CREATESIMPLECHROMESYSROOTREQUEST.fields_by_name['build_target'].message_type = chromiumos_dot_common__pb2._BUILDTARGET
 _CREATESIMPLECHROMESYSROOTREQUEST.fields_by_name['target_dir'].message_type = chromiumos_dot_common__pb2._RESULTPATH
 _CREATESIMPLECHROMESYSROOTREQUEST.fields_by_name['chroot'].message_type = chromiumos_dot_common__pb2._CHROOT
@@ -721,6 +785,7 @@
 DESCRIPTOR.message_types_by_name['InstallToolchainResponse'] = _INSTALLTOOLCHAINRESPONSE
 DESCRIPTOR.message_types_by_name['InstallPackagesRequest'] = _INSTALLPACKAGESREQUEST
 DESCRIPTOR.message_types_by_name['InstallPackagesResponse'] = _INSTALLPACKAGESRESPONSE
+DESCRIPTOR.message_types_by_name['FailedPackageData'] = _FAILEDPACKAGEDATA
 DESCRIPTOR.message_types_by_name['CreateSimpleChromeSysrootRequest'] = _CREATESIMPLECHROMESYSROOTREQUEST
 DESCRIPTOR.message_types_by_name['CreateSimpleChromeSysrootResponse'] = _CREATESIMPLECHROMESYSROOTRESPONSE
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
@@ -819,6 +884,13 @@
   })
 _sym_db.RegisterMessage(InstallPackagesResponse)
 
+FailedPackageData = _reflection.GeneratedProtocolMessageType('FailedPackageData', (_message.Message,), {
+  'DESCRIPTOR' : _FAILEDPACKAGEDATA,
+  '__module__' : 'chromite.api.sysroot_pb2'
+  # @@protoc_insertion_point(class_scope:chromite.api.FailedPackageData)
+  })
+_sym_db.RegisterMessage(FailedPackageData)
+
 CreateSimpleChromeSysrootRequest = _reflection.GeneratedProtocolMessageType('CreateSimpleChromeSysrootRequest', (_message.Message,), {
   'DESCRIPTOR' : _CREATESIMPLECHROMESYSROOTREQUEST,
   '__module__' : 'chromite.api.sysroot_pb2'
@@ -842,8 +914,8 @@
   file=DESCRIPTOR,
   index=0,
   serialized_options=b'\302\355\032\013\n\007sysroot\020\001',
-  serialized_start=2098,
-  serialized_end=2645,
+  serialized_start=2399,
+  serialized_end=2946,
   methods=[
   _descriptor.MethodDescriptor(
     name='Create',
diff --git a/api/gen_sdk/chromite/api/test_pb2.py b/api/gen_sdk/chromite/api/test_pb2.py
index b880596..46043b9 100644
--- a/api/gen_sdk/chromite/api/test_pb2.py
+++ b/api/gen_sdk/chromite/api/test_pb2.py
@@ -15,9 +15,7 @@
 from chromite.api.gen_sdk.chromite.api import sysroot_pb2 as chromite_dot_api_dot_sysroot__pb2
 from chromite.api.gen_sdk.chromiumos import common_pb2 as chromiumos_dot_common__pb2
 from chromite.api.gen_sdk.chromiumos import metrics_pb2 as chromiumos_dot_metrics__pb2
-from chromite.api.gen_sdk.chromiumos.test.api import coverage_rule_pb2 as chromiumos_dot_test_dot_api_dot_coverage__rule__pb2
 from chromite.api.gen_sdk.chromiumos.build.api import container_metadata_pb2 as chromiumos_dot_build_dot_api_dot_container__metadata__pb2
-from chromite.api.gen_sdk.chromiumos.test.plan import source_test_plan_pb2 as chromiumos_dot_test_dot_plan_dot_source__test__plan__pb2
 
 
 DESCRIPTOR = _descriptor.FileDescriptor(
@@ -25,9 +23,9 @@
   package='chromite.api',
   syntax='proto3',
   serialized_options=b'Z6go.chromium.org/chromiumos/infra/proto/go/chromite/api',
-  serialized_pb=b'\n\x17\x63hromite/api/test.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x1a\x63hromite/api/sysroot.proto\x1a\x17\x63hromiumos/common.proto\x1a\x18\x63hromiumos/metrics.proto\x1a\'chromiumos/test/api/coverage_rule.proto\x1a-chromiumos/build/api/container_metadata.proto\x1a+chromiumos/test/plan/source_test_plan.proto\"\xcf\x02\n\x1fTestServiceContainerBuildResult\x12\x0c\n\x04name\x18\x01 \x01(\t\x12H\n\x07success\x18\x02 \x01(\x0b\x32\x35.chromite.api.TestServiceContainerBuildResult.SuccessH\x00\x12H\n\x07\x66\x61ilure\x18\x03 \x01(\x0b\x32\x35.chromite.api.TestServiceContainerBuildResult.FailureH\x00\x1a^\n\x07Success\x12<\n\nimage_info\x18\x02 \x01(\x0b\x32(.chromiumos.build.api.ContainerImageInfo\x12\x15\n\rregistry_path\x18\x01 \x01(\t\x1a \n\x07\x46\x61ilure\x12\x15\n\rerror_message\x18\x01 \x01(\tB\x08\n\x06result\"\xca\x02\n!BuildTestServiceContainersRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x0f\n\x07version\x18\x03 \x01(\t\x12\x37\n\nrepository\x18\x04 \x01(\x0b\x32#.chromiumos.build.api.GcrRepository\x12\x0c\n\x04tags\x18\x05 \x03(\t\x12K\n\x06labels\x18\x06 \x03(\x0b\x32;.chromite.api.BuildTestServiceContainersRequest.LabelsEntry\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"d\n\"BuildTestServiceContainersResponse\x12>\n\x07results\x18\x01 \x03(\x0b\x32-.chromite.api.TestServiceContainerBuildResult\"\xc0\x03\n\x1a\x42uildTargetUnitTestRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x13\n\x0bresult_path\x18\x02 \x01(\t\x12\"\n\x06\x63hroot\x18\x03 \x01(\x0b\x32\x12.chromiumos.Chroot\x12=\n\x05\x66lags\x18\x04 \x01(\x0b\x32..chromite.api.BuildTargetUnitTestRequest.Flags\x12)\n\x08packages\x18\x06 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\x32\n\x11package_blocklist\x18\x07 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x1a\x95\x01\n\x05\x46lags\x12\x15\n\rempty_sysroot\x18\x01 \x01(\x08\x12\x19\n\x11toolchain_changed\x18\x02 \x01(\x08\x12\x15\n\rcode_coverage\x18\x03 \x01(\x08\x12\"\n\x1atestable_packages_optional\x18\x04 \x01(\x08\x12\x1f\n\x17\x66ilter_only_cros_workon\x18\x05 \x01(\x08J\x04\x08\x05\x10\x06\"\x8e\x01\n\x1b\x42uildTargetUnitTestResponse\x12\x14\n\x0ctarball_path\x18\x01 \x01(\t\x12\x30\n\x0f\x66\x61iled_packages\x18\x02 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\'\n\x06\x65vents\x18\x03 \x03(\x0b\x32\x17.chromiumos.MetricEvent\"=\n\x17\x43hromiteUnitTestRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x1a\n\x18\x43hromiteUnitTestResponse\";\n\x15\x43hromitePytestRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x18\n\x16\x43hromitePytestResponse\"<\n\x16\x43rosSigningTestRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x19\n\x17\x43rosSigningTestResponse\"b\n\x14\x44\x65\x62ugInfoTestRequest\x12&\n\x07sysroot\x18\x01 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x17\n\x15\x44\x65\x62ugInfoTestResponse\"\xd2\x03\n\rVmTestRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12!\n\x07vm_path\x18\x03 \x01(\x0b\x32\x10.chromiumos.Path\x12;\n\x0bssh_options\x18\x04 \x01(\x0b\x32&.chromite.api.VmTestRequest.SshOptions\x12=\n\x0ctest_harness\x18\x05 \x01(\x0e\x32\'.chromite.api.VmTestRequest.TestHarness\x12\x34\n\x08vm_tests\x18\x06 \x03(\x0b\x32\".chromite.api.VmTestRequest.VmTest\x1a\x46\n\nSshOptions\x12*\n\x10private_key_path\x18\x01 \x01(\x0b\x32\x10.chromiumos.Path\x12\x0c\n\x04port\x18\x02 \x01(\x05\x1a\x19\n\x06VmTest\x12\x0f\n\x07pattern\x18\x01 \x01(\t\"6\n\x0bTestHarness\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x08\n\x04TAST\x10\x01\x12\x0c\n\x08\x41UTOTEST\x10\x02\"\x10\n\x0eVmTestResponse\"\xe9\x01\n\x13MoblabVmTestRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12@\n\rimage_payload\x18\x02 \x01(\x0b\x32).chromite.api.MoblabVmTestRequest.Payload\x12\x41\n\x0e\x63\x61\x63he_payloads\x18\x03 \x03(\x0b\x32).chromite.api.MoblabVmTestRequest.Payload\x1a)\n\x07Payload\x12\x1e\n\x04path\x18\x01 \x01(\x0b\x32\x10.chromiumos.Path\"\x16\n\x14MoblabVmTestResponse\"\x8b\x01\n\x1fSimpleChromeWorkflowTestRequest\x12&\n\x07sysroot\x18\x01 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\x13\n\x0b\x63hrome_root\x18\x02 \x01(\t\x12+\n\x0bgoma_config\x18\x03 \x01(\x0b\x32\x16.chromiumos.GomaConfig\"\"\n SimpleChromeWorkflowTestResponse\"\x87\x02\n\x17GetCoverageRulesRequest\x12\"\n\x06\x63hroot\x18\x05 \x01(\x0b\x32\x12.chromiumos.Chroot\x12?\n\x11source_test_plans\x18\x01 \x03(\x0b\x32$.chromiumos.test.plan.SourceTestPlan\x12-\n\x13\x62uild_metadata_list\x18\x02 \x01(\x0b\x32\x10.chromiumos.Path\x12,\n\x12\x64ut_attribute_list\x18\x03 \x01(\x0b\x32\x10.chromiumos.Path\x12*\n\x10\x66lat_config_list\x18\x04 \x01(\x0b\x32\x10.chromiumos.Path\"U\n\x18GetCoverageRulesResponse\x12\x39\n\x0e\x63overage_rules\x18\x01 \x03(\x0b\x32!.chromiumos.test.api.CoverageRule2\x9e\x08\n\x0bTestService\x12\x87\x01\n\x1a\x42uildTestServiceContainers\x12/.chromite.api.BuildTestServiceContainersRequest\x1a\x30.chromite.api.BuildTestServiceContainersResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x12r\n\x13\x42uildTargetUnitTest\x12(.chromite.api.BuildTargetUnitTestRequest\x1a).chromite.api.BuildTargetUnitTestResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x12\x61\n\x10\x43hromiteUnitTest\x12%.chromite.api.ChromiteUnitTestRequest\x1a&.chromite.api.ChromiteUnitTestResponse\x12[\n\x0e\x43hromitePytest\x12#.chromite.api.ChromitePytestRequest\x1a$.chromite.api.ChromitePytestResponse\x12^\n\x0f\x43rosSigningTest\x12$.chromite.api.CrosSigningTestRequest\x1a%.chromite.api.CrosSigningTestResponse\x12X\n\rDebugInfoTest\x12\".chromite.api.DebugInfoTestRequest\x1a#.chromite.api.DebugInfoTestResponse\x12\x43\n\x06VmTest\x12\x1b.chromite.api.VmTestRequest\x1a\x1c.chromite.api.VmTestResponse\x12]\n\x0cMoblabVmTest\x12!.chromite.api.MoblabVmTestRequest\x1a\".chromite.api.MoblabVmTestResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x12\x81\x01\n\x18SimpleChromeWorkflowTest\x12-.chromite.api.SimpleChromeWorkflowTestRequest\x1a..chromite.api.SimpleChromeWorkflowTestResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x12\x61\n\x10GetCoverageRules\x12%.chromite.api.GetCoverageRulesRequest\x1a&.chromite.api.GetCoverageRulesResponse\x1a\x0c\xc2\xed\x1a\x08\n\x04test\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
+  serialized_pb=b'\n\x17\x63hromite/api/test.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/build_api.proto\x1a\x1a\x63hromite/api/sysroot.proto\x1a\x17\x63hromiumos/common.proto\x1a\x18\x63hromiumos/metrics.proto\x1a-chromiumos/build/api/container_metadata.proto\"\xcf\x02\n\x1fTestServiceContainerBuildResult\x12\x0c\n\x04name\x18\x01 \x01(\t\x12H\n\x07success\x18\x02 \x01(\x0b\x32\x35.chromite.api.TestServiceContainerBuildResult.SuccessH\x00\x12H\n\x07\x66\x61ilure\x18\x03 \x01(\x0b\x32\x35.chromite.api.TestServiceContainerBuildResult.FailureH\x00\x1a^\n\x07Success\x12<\n\nimage_info\x18\x02 \x01(\x0b\x32(.chromiumos.build.api.ContainerImageInfo\x12\x15\n\rregistry_path\x18\x01 \x01(\t\x1a \n\x07\x46\x61ilure\x12\x15\n\rerror_message\x18\x01 \x01(\tB\x08\n\x06result\"\xca\x02\n!BuildTestServiceContainersRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12\x0f\n\x07version\x18\x03 \x01(\t\x12\x37\n\nrepository\x18\x04 \x01(\x0b\x32#.chromiumos.build.api.GcrRepository\x12\x0c\n\x04tags\x18\x05 \x03(\t\x12K\n\x06labels\x18\x06 \x03(\x0b\x32;.chromite.api.BuildTestServiceContainersRequest.LabelsEntry\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"d\n\"BuildTestServiceContainersResponse\x12>\n\x07results\x18\x01 \x03(\x0b\x32-.chromite.api.TestServiceContainerBuildResult\"\xc0\x03\n\x1a\x42uildTargetUnitTestRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x13\n\x0bresult_path\x18\x02 \x01(\t\x12\"\n\x06\x63hroot\x18\x03 \x01(\x0b\x32\x12.chromiumos.Chroot\x12=\n\x05\x66lags\x18\x04 \x01(\x0b\x32..chromite.api.BuildTargetUnitTestRequest.Flags\x12)\n\x08packages\x18\x06 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\x32\n\x11package_blocklist\x18\x07 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x1a\x95\x01\n\x05\x46lags\x12\x15\n\rempty_sysroot\x18\x01 \x01(\x08\x12\x19\n\x11toolchain_changed\x18\x02 \x01(\x08\x12\x15\n\rcode_coverage\x18\x03 \x01(\x08\x12\"\n\x1atestable_packages_optional\x18\x04 \x01(\x08\x12\x1f\n\x17\x66ilter_only_cros_workon\x18\x05 \x01(\x08J\x04\x08\x05\x10\x06\"\xcc\x01\n\x1b\x42uildTargetUnitTestResponse\x12\x14\n\x0ctarball_path\x18\x01 \x01(\t\x12\x30\n\x0f\x66\x61iled_packages\x18\x02 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\'\n\x06\x65vents\x18\x03 \x03(\x0b\x32\x17.chromiumos.MetricEvent\x12<\n\x13\x66\x61iled_package_data\x18\x04 \x03(\x0b\x32\x1f.chromite.api.FailedPackageData\"=\n\x17\x43hromiteUnitTestRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x1a\n\x18\x43hromiteUnitTestResponse\";\n\x15\x43hromitePytestRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x18\n\x16\x43hromitePytestResponse\"<\n\x16\x43rosSigningTestRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x19\n\x17\x43rosSigningTestResponse\"b\n\x14\x44\x65\x62ugInfoTestRequest\x12&\n\x07sysroot\x18\x01 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\"\x17\n\x15\x44\x65\x62ugInfoTestResponse\"\xd2\x03\n\rVmTestRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12!\n\x07vm_path\x18\x03 \x01(\x0b\x32\x10.chromiumos.Path\x12;\n\x0bssh_options\x18\x04 \x01(\x0b\x32&.chromite.api.VmTestRequest.SshOptions\x12=\n\x0ctest_harness\x18\x05 \x01(\x0e\x32\'.chromite.api.VmTestRequest.TestHarness\x12\x34\n\x08vm_tests\x18\x06 \x03(\x0b\x32\".chromite.api.VmTestRequest.VmTest\x1a\x46\n\nSshOptions\x12*\n\x10private_key_path\x18\x01 \x01(\x0b\x32\x10.chromiumos.Path\x12\x0c\n\x04port\x18\x02 \x01(\x05\x1a\x19\n\x06VmTest\x12\x0f\n\x07pattern\x18\x01 \x01(\t\"6\n\x0bTestHarness\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x08\n\x04TAST\x10\x01\x12\x0c\n\x08\x41UTOTEST\x10\x02\"\x10\n\x0eVmTestResponse\"\xe9\x01\n\x13MoblabVmTestRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12@\n\rimage_payload\x18\x02 \x01(\x0b\x32).chromite.api.MoblabVmTestRequest.Payload\x12\x41\n\x0e\x63\x61\x63he_payloads\x18\x03 \x03(\x0b\x32).chromite.api.MoblabVmTestRequest.Payload\x1a)\n\x07Payload\x12\x1e\n\x04path\x18\x01 \x01(\x0b\x32\x10.chromiumos.Path\"\x16\n\x14MoblabVmTestResponse\"\x8b\x01\n\x1fSimpleChromeWorkflowTestRequest\x12&\n\x07sysroot\x18\x01 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\x13\n\x0b\x63hrome_root\x18\x02 \x01(\t\x12+\n\x0bgoma_config\x18\x03 \x01(\x0b\x32\x16.chromiumos.GomaConfig\"\"\n SimpleChromeWorkflowTestResponse2\xbb\x07\n\x0bTestService\x12\x87\x01\n\x1a\x42uildTestServiceContainers\x12/.chromite.api.BuildTestServiceContainersRequest\x1a\x30.chromite.api.BuildTestServiceContainersResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x12r\n\x13\x42uildTargetUnitTest\x12(.chromite.api.BuildTargetUnitTestRequest\x1a).chromite.api.BuildTargetUnitTestResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x12\x61\n\x10\x43hromiteUnitTest\x12%.chromite.api.ChromiteUnitTestRequest\x1a&.chromite.api.ChromiteUnitTestResponse\x12[\n\x0e\x43hromitePytest\x12#.chromite.api.ChromitePytestRequest\x1a$.chromite.api.ChromitePytestResponse\x12^\n\x0f\x43rosSigningTest\x12$.chromite.api.CrosSigningTestRequest\x1a%.chromite.api.CrosSigningTestResponse\x12X\n\rDebugInfoTest\x12\".chromite.api.DebugInfoTestRequest\x1a#.chromite.api.DebugInfoTestResponse\x12\x43\n\x06VmTest\x12\x1b.chromite.api.VmTestRequest\x1a\x1c.chromite.api.VmTestResponse\x12]\n\x0cMoblabVmTest\x12!.chromite.api.MoblabVmTestRequest\x1a\".chromite.api.MoblabVmTestResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x12\x81\x01\n\x18SimpleChromeWorkflowTest\x12-.chromite.api.SimpleChromeWorkflowTestRequest\x1a..chromite.api.SimpleChromeWorkflowTestResponse\"\x06\xc2\xed\x1a\x02\x10\x02\x1a\x0c\xc2\xed\x1a\x08\n\x04test\x10\x01\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
   ,
-  dependencies=[chromite_dot_api_dot_build__api__pb2.DESCRIPTOR,chromite_dot_api_dot_sysroot__pb2.DESCRIPTOR,chromiumos_dot_common__pb2.DESCRIPTOR,chromiumos_dot_metrics__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_coverage__rule__pb2.DESCRIPTOR,chromiumos_dot_build_dot_api_dot_container__metadata__pb2.DESCRIPTOR,chromiumos_dot_test_dot_plan_dot_source__test__plan__pb2.DESCRIPTOR,])
+  dependencies=[chromite_dot_api_dot_build__api__pb2.DESCRIPTOR,chromite_dot_api_dot_sysroot__pb2.DESCRIPTOR,chromiumos_dot_common__pb2.DESCRIPTOR,chromiumos_dot_metrics__pb2.DESCRIPTOR,chromiumos_dot_build_dot_api_dot_container__metadata__pb2.DESCRIPTOR,])
 
 
 
@@ -52,8 +50,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2457,
-  serialized_end=2511,
+  serialized_start=2433,
+  serialized_end=2487,
 )
 _sym_db.RegisterEnumDescriptor(_VMTESTREQUEST_TESTHARNESS)
 
@@ -91,8 +89,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=481,
-  serialized_end=575,
+  serialized_start=395,
+  serialized_end=489,
 )
 
 _TESTSERVICECONTAINERBUILDRESULT_FAILURE = _descriptor.Descriptor(
@@ -121,8 +119,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=577,
-  serialized_end=609,
+  serialized_start=491,
+  serialized_end=523,
 )
 
 _TESTSERVICECONTAINERBUILDRESULT = _descriptor.Descriptor(
@@ -168,8 +166,8 @@
       name='result', full_name='chromite.api.TestServiceContainerBuildResult.result',
       index=0, containing_type=None, fields=[]),
   ],
-  serialized_start=284,
-  serialized_end=619,
+  serialized_start=198,
+  serialized_end=533,
 )
 
 
@@ -206,8 +204,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=907,
-  serialized_end=952,
+  serialized_start=821,
+  serialized_end=866,
 )
 
 _BUILDTESTSERVICECONTAINERSREQUEST = _descriptor.Descriptor(
@@ -271,8 +269,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=622,
-  serialized_end=952,
+  serialized_start=536,
+  serialized_end=866,
 )
 
 
@@ -302,8 +300,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=954,
-  serialized_end=1054,
+  serialized_start=868,
+  serialized_end=968,
 )
 
 
@@ -361,8 +359,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1350,
-  serialized_end=1499,
+  serialized_start=1264,
+  serialized_end=1413,
 )
 
 _BUILDTARGETUNITTESTREQUEST = _descriptor.Descriptor(
@@ -426,8 +424,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1057,
-  serialized_end=1505,
+  serialized_start=971,
+  serialized_end=1419,
 )
 
 
@@ -459,6 +457,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='failed_package_data', full_name='chromite.api.BuildTargetUnitTestResponse.failed_package_data', index=3,
+      number=4, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -471,8 +476,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1508,
-  serialized_end=1650,
+  serialized_start=1422,
+  serialized_end=1626,
 )
 
 
@@ -502,8 +507,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1652,
-  serialized_end=1713,
+  serialized_start=1628,
+  serialized_end=1689,
 )
 
 
@@ -526,8 +531,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1715,
-  serialized_end=1741,
+  serialized_start=1691,
+  serialized_end=1717,
 )
 
 
@@ -557,8 +562,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1743,
-  serialized_end=1802,
+  serialized_start=1719,
+  serialized_end=1778,
 )
 
 
@@ -581,8 +586,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1804,
-  serialized_end=1828,
+  serialized_start=1780,
+  serialized_end=1804,
 )
 
 
@@ -612,8 +617,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1830,
-  serialized_end=1890,
+  serialized_start=1806,
+  serialized_end=1866,
 )
 
 
@@ -636,8 +641,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1892,
-  serialized_end=1917,
+  serialized_start=1868,
+  serialized_end=1893,
 )
 
 
@@ -674,8 +679,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1919,
-  serialized_end=2017,
+  serialized_start=1895,
+  serialized_end=1993,
 )
 
 
@@ -698,8 +703,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2019,
-  serialized_end=2042,
+  serialized_start=1995,
+  serialized_end=2018,
 )
 
 
@@ -736,8 +741,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2358,
-  serialized_end=2428,
+  serialized_start=2334,
+  serialized_end=2404,
 )
 
 _VMTESTREQUEST_VMTEST = _descriptor.Descriptor(
@@ -766,8 +771,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2430,
-  serialized_end=2455,
+  serialized_start=2406,
+  serialized_end=2431,
 )
 
 _VMTESTREQUEST = _descriptor.Descriptor(
@@ -832,8 +837,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2045,
-  serialized_end=2511,
+  serialized_start=2021,
+  serialized_end=2487,
 )
 
 
@@ -856,8 +861,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2513,
-  serialized_end=2529,
+  serialized_start=2489,
+  serialized_end=2505,
 )
 
 
@@ -887,8 +892,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2724,
-  serialized_end=2765,
+  serialized_start=2700,
+  serialized_end=2741,
 )
 
 _MOBLABVMTESTREQUEST = _descriptor.Descriptor(
@@ -931,8 +936,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2532,
-  serialized_end=2765,
+  serialized_start=2508,
+  serialized_end=2741,
 )
 
 
@@ -955,8 +960,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2767,
-  serialized_end=2789,
+  serialized_start=2743,
+  serialized_end=2765,
 )
 
 
@@ -1000,8 +1005,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2792,
-  serialized_end=2931,
+  serialized_start=2768,
+  serialized_end=2907,
 )
 
 
@@ -1024,98 +1029,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2933,
-  serialized_end=2967,
-)
-
-
-_GETCOVERAGERULESREQUEST = _descriptor.Descriptor(
-  name='GetCoverageRulesRequest',
-  full_name='chromite.api.GetCoverageRulesRequest',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='chroot', full_name='chromite.api.GetCoverageRulesRequest.chroot', index=0,
-      number=5, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='source_test_plans', full_name='chromite.api.GetCoverageRulesRequest.source_test_plans', index=1,
-      number=1, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='build_metadata_list', full_name='chromite.api.GetCoverageRulesRequest.build_metadata_list', index=2,
-      number=2, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='dut_attribute_list', full_name='chromite.api.GetCoverageRulesRequest.dut_attribute_list', index=3,
-      number=3, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='flat_config_list', full_name='chromite.api.GetCoverageRulesRequest.flat_config_list', index=4,
-      number=4, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=2970,
-  serialized_end=3233,
-)
-
-
-_GETCOVERAGERULESRESPONSE = _descriptor.Descriptor(
-  name='GetCoverageRulesResponse',
-  full_name='chromite.api.GetCoverageRulesResponse',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='coverage_rules', full_name='chromite.api.GetCoverageRulesResponse.coverage_rules', index=0,
-      number=1, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=3235,
-  serialized_end=3320,
+  serialized_start=2909,
+  serialized_end=2943,
 )
 
 _TESTSERVICECONTAINERBUILDRESULT_SUCCESS.fields_by_name['image_info'].message_type = chromiumos_dot_build_dot_api_dot_container__metadata__pb2._CONTAINERIMAGEINFO
@@ -1143,6 +1058,7 @@
 _BUILDTARGETUNITTESTREQUEST.fields_by_name['package_blocklist'].message_type = chromiumos_dot_common__pb2._PACKAGEINFO
 _BUILDTARGETUNITTESTRESPONSE.fields_by_name['failed_packages'].message_type = chromiumos_dot_common__pb2._PACKAGEINFO
 _BUILDTARGETUNITTESTRESPONSE.fields_by_name['events'].message_type = chromiumos_dot_metrics__pb2._METRICEVENT
+_BUILDTARGETUNITTESTRESPONSE.fields_by_name['failed_package_data'].message_type = chromite_dot_api_dot_sysroot__pb2._FAILEDPACKAGEDATA
 _CHROMITEUNITTESTREQUEST.fields_by_name['chroot'].message_type = chromiumos_dot_common__pb2._CHROOT
 _CHROMITEPYTESTREQUEST.fields_by_name['chroot'].message_type = chromiumos_dot_common__pb2._CHROOT
 _CROSSIGNINGTESTREQUEST.fields_by_name['chroot'].message_type = chromiumos_dot_common__pb2._CHROOT
@@ -1165,12 +1081,6 @@
 _MOBLABVMTESTREQUEST.fields_by_name['cache_payloads'].message_type = _MOBLABVMTESTREQUEST_PAYLOAD
 _SIMPLECHROMEWORKFLOWTESTREQUEST.fields_by_name['sysroot'].message_type = chromite_dot_api_dot_sysroot__pb2._SYSROOT
 _SIMPLECHROMEWORKFLOWTESTREQUEST.fields_by_name['goma_config'].message_type = chromiumos_dot_common__pb2._GOMACONFIG
-_GETCOVERAGERULESREQUEST.fields_by_name['chroot'].message_type = chromiumos_dot_common__pb2._CHROOT
-_GETCOVERAGERULESREQUEST.fields_by_name['source_test_plans'].message_type = chromiumos_dot_test_dot_plan_dot_source__test__plan__pb2._SOURCETESTPLAN
-_GETCOVERAGERULESREQUEST.fields_by_name['build_metadata_list'].message_type = chromiumos_dot_common__pb2._PATH
-_GETCOVERAGERULESREQUEST.fields_by_name['dut_attribute_list'].message_type = chromiumos_dot_common__pb2._PATH
-_GETCOVERAGERULESREQUEST.fields_by_name['flat_config_list'].message_type = chromiumos_dot_common__pb2._PATH
-_GETCOVERAGERULESRESPONSE.fields_by_name['coverage_rules'].message_type = chromiumos_dot_test_dot_api_dot_coverage__rule__pb2._COVERAGERULE
 DESCRIPTOR.message_types_by_name['TestServiceContainerBuildResult'] = _TESTSERVICECONTAINERBUILDRESULT
 DESCRIPTOR.message_types_by_name['BuildTestServiceContainersRequest'] = _BUILDTESTSERVICECONTAINERSREQUEST
 DESCRIPTOR.message_types_by_name['BuildTestServiceContainersResponse'] = _BUILDTESTSERVICECONTAINERSRESPONSE
@@ -1190,8 +1100,6 @@
 DESCRIPTOR.message_types_by_name['MoblabVmTestResponse'] = _MOBLABVMTESTRESPONSE
 DESCRIPTOR.message_types_by_name['SimpleChromeWorkflowTestRequest'] = _SIMPLECHROMEWORKFLOWTESTREQUEST
 DESCRIPTOR.message_types_by_name['SimpleChromeWorkflowTestResponse'] = _SIMPLECHROMEWORKFLOWTESTRESPONSE
-DESCRIPTOR.message_types_by_name['GetCoverageRulesRequest'] = _GETCOVERAGERULESREQUEST
-DESCRIPTOR.message_types_by_name['GetCoverageRulesResponse'] = _GETCOVERAGERULESRESPONSE
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
 TestServiceContainerBuildResult = _reflection.GeneratedProtocolMessageType('TestServiceContainerBuildResult', (_message.Message,), {
@@ -1383,20 +1291,6 @@
   })
 _sym_db.RegisterMessage(SimpleChromeWorkflowTestResponse)
 
-GetCoverageRulesRequest = _reflection.GeneratedProtocolMessageType('GetCoverageRulesRequest', (_message.Message,), {
-  'DESCRIPTOR' : _GETCOVERAGERULESREQUEST,
-  '__module__' : 'chromite.api.test_pb2'
-  # @@protoc_insertion_point(class_scope:chromite.api.GetCoverageRulesRequest)
-  })
-_sym_db.RegisterMessage(GetCoverageRulesRequest)
-
-GetCoverageRulesResponse = _reflection.GeneratedProtocolMessageType('GetCoverageRulesResponse', (_message.Message,), {
-  'DESCRIPTOR' : _GETCOVERAGERULESRESPONSE,
-  '__module__' : 'chromite.api.test_pb2'
-  # @@protoc_insertion_point(class_scope:chromite.api.GetCoverageRulesResponse)
-  })
-_sym_db.RegisterMessage(GetCoverageRulesResponse)
-
 
 DESCRIPTOR._options = None
 _BUILDTESTSERVICECONTAINERSREQUEST_LABELSENTRY._options = None
@@ -1407,8 +1301,8 @@
   file=DESCRIPTOR,
   index=0,
   serialized_options=b'\302\355\032\010\n\004test\020\001',
-  serialized_start=3323,
-  serialized_end=4377,
+  serialized_start=2946,
+  serialized_end=3901,
   methods=[
   _descriptor.MethodDescriptor(
     name='BuildTestServiceContainers',
@@ -1491,15 +1385,6 @@
     output_type=_SIMPLECHROMEWORKFLOWTESTRESPONSE,
     serialized_options=b'\302\355\032\002\020\002',
   ),
-  _descriptor.MethodDescriptor(
-    name='GetCoverageRules',
-    full_name='chromite.api.TestService.GetCoverageRules',
-    index=9,
-    containing_service=None,
-    input_type=_GETCOVERAGERULESREQUEST,
-    output_type=_GETCOVERAGERULESRESPONSE,
-    serialized_options=None,
-  ),
 ])
 _sym_db.RegisterServiceDescriptor(_TESTSERVICE)
 
diff --git a/api/gen_sdk/chromite/api/toolchain_pb2.py b/api/gen_sdk/chromite/api/toolchain_pb2.py
index b304f57..6bac931 100644
--- a/api/gen_sdk/chromite/api/toolchain_pb2.py
+++ b/api/gen_sdk/chromite/api/toolchain_pb2.py
@@ -2,7 +2,6 @@
 # Generated by the protocol buffer compiler.  DO NOT EDIT!
 # source: chromite/api/toolchain.proto
 
-from google.protobuf.internal import enum_type_wrapper
 from google.protobuf import descriptor as _descriptor
 from google.protobuf import message as _message
 from google.protobuf import reflection as _reflection
@@ -24,51 +23,37 @@
   package='chromite.api',
   syntax='proto3',
   serialized_options=b'Z6go.chromium.org/chromiumos/infra/proto/go/chromite/api',
-  serialized_pb=b'\n\x1c\x63hromite/api/toolchain.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/artifacts.proto\x1a\x1c\x63hromite/api/build_api.proto\x1a\x1a\x63hromite/api/sysroot.proto\x1a\x1f\x63hromiumos/builder_config.proto\x1a\x17\x63hromiumos/common.proto\"\x83\x01\n\x0c\x41rtifactInfo\x12H\n\rartifact_type\x18\x01 \x01(\x0e\x32\x31.chromiumos.BuilderConfig.Artifacts.ArtifactTypes\x12)\n\tartifacts\x18\x02 \x03(\x0b\x32\x16.chromite.api.Artifact\"\x83\x03\n\x1fPrepareForToolchainBuildRequest\x12I\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x31.chromiumos.BuilderConfig.Artifacts.ArtifactTypes\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x03 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12N\n\x0finput_artifacts\x18\x04 \x03(\x0b\x32\x35.chromiumos.BuilderConfig.Artifacts.InputArtifactInfo\x12\x42\n\x0f\x61\x64\x64itional_args\x18\x05 \x01(\x0b\x32).chromiumos.PrepareForBuildAdditionalArgs\x12\x35\n\x0cprofile_info\x18\x06 \x01(\x0b\x32\x1f.chromiumos.ArtifactProfileInfo\"q\n PrepareForToolchainBuildResponse\x12M\n\x0f\x62uild_relevance\x18\x01 \x01(\x0e\x32\x34.chromite.api.PrepareForBuildResponse.BuildRelevance\"\xbe\x02\n\x16\x42undleToolchainRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\x12\n\noutput_dir\x18\x03 \x01(\t\x12I\n\x0e\x61rtifact_types\x18\x04 \x03(\x0e\x32\x31.chromiumos.BuilderConfig.Artifacts.ArtifactTypes\x12\x42\n\x0f\x61\x64\x64itional_args\x18\x05 \x01(\x0b\x32).chromiumos.PrepareForBuildAdditionalArgs\x12\x35\n\x0cprofile_info\x18\x06 \x01(\x0b\x32\x1f.chromiumos.ArtifactProfileInfo\"S\n\x17\x42undleToolchainResponse\x12\x32\n\x0e\x61rtifacts_info\x18\x02 \x03(\x0b\x32\x1a.chromite.api.ArtifactInfoJ\x04\x08\x01\x10\x02\"\xeb\x01\n\x16GetUpdatedFilesRequest\x12R\n\x12uploaded_artifacts\x18\x01 \x03(\x0b\x32\x36.chromite.api.GetUpdatedFilesRequest.UploadedArtifacts\x1a}\n\x11UploadedArtifacts\x12\x31\n\rartifact_info\x18\x01 \x01(\x0b\x32\x1a.chromite.api.ArtifactInfo\x12\x35\n\x0cprofile_info\x18\x02 \x01(\x0b\x32\x1f.chromiumos.ArtifactProfileInfo\"\xf4\x03\n\x17GetUpdatedFilesResponse\x12H\n\rupdated_files\x18\x01 \x03(\x0b\x32\x31.chromite.api.GetUpdatedFilesResponse.UpdatedFile\x12\x16\n\x0e\x63ommit_message\x18\x02 \x01(\t\x12I\n\rcommit_footer\x18\x03 \x03(\x0b\x32\x32.chromite.api.GetUpdatedFilesResponse.CommitFooter\x1a\x1b\n\x0bUpdatedFile\x12\x0c\n\x04path\x18\x01 \x01(\t\x1a\x41\n\x0e\x43qDependFooter\x12/\n\rgerrit_change\x18\x01 \x03(\x0b\x32\x18.chromiumos.GerritChange\x1a\x1c\n\rCqClTagFooter\x12\x0b\n\x03tag\x18\x01 \x01(\t\x1a\xad\x01\n\x0c\x43ommitFooter\x12I\n\tcq_depend\x18\x01 \x01(\x0b\x32\x34.chromite.api.GetUpdatedFilesResponse.CqDependFooterH\x00\x12H\n\tcq_cl_tag\x18\x02 \x01(\x0b\x32\x33.chromite.api.GetUpdatedFilesResponse.CqClTagFooterH\x00\x42\x08\n\x06\x66ooter\"\x80\x01\n\x1aVerifyAFDOArtifactsRequest\x12-\n\x0c\x62uild_target\x18\x01 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x33\n\rartifact_type\x18\x02 \x01(\x0e\x32\x1c.chromiumos.AFDOArtifactType\"-\n\x1bVerifyAFDOArtifactsResponse\x12\x0e\n\x06status\x18\x01 \x01(\x08\"X\n\rLinterFinding\x12\x0f\n\x07message\x18\x01 \x01(\t\x12\x36\n\tlocations\x18\x02 \x03(\x0b\x32#.chromite.api.LinterFindingLocation\"O\n\x15LinterFindingLocation\x12\x10\n\x08\x66ilepath\x18\x01 \x01(\t\x12\x12\n\nline_start\x18\x02 \x01(\x05\x12\x10\n\x08line_end\x18\x03 \x01(\x05\"\x86\x01\n\rLinterRequest\x12)\n\x08packages\x18\x01 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\"\n\x06\x63hroot\x18\x03 \x01(\x0b\x32\x12.chromiumos.Chroot\"?\n\x0eLinterResponse\x12-\n\x08\x66indings\x18\x01 \x03(\x0b\x32\x1b.chromite.api.LinterFinding*f\n\x10\x41\x46\x44OArtifactType\x12\r\n\tNONE_TYPE\x10\x00\x12\r\n\tORDERFILE\x10\x01\x12\x12\n\x0e\x42\x45NCHMARK_AFDO\x10\x02\x12\x0f\n\x0bKERNEL_AFDO\x10\x03\x12\x0f\n\x0b\x43HROME_AFDO\x10\x04\x32\xa4\x05\n\x10ToolchainService\x12|\n\x1dUpdateEbuildWithAFDOArtifacts\x12(.chromite.api.VerifyAFDOArtifactsRequest\x1a).chromite.api.VerifyAFDOArtifactsResponse\"\x06\xc2\xed\x1a\x02\x10\x01\x12x\n\x19UploadVettedAFDOArtifacts\x12(.chromite.api.VerifyAFDOArtifactsRequest\x1a).chromite.api.VerifyAFDOArtifactsResponse\"\x06\xc2\xed\x1a\x02\x10\x01\x12p\n\x0fPrepareForBuild\x12-.chromite.api.PrepareForToolchainBuildRequest\x1a..chromite.api.PrepareForToolchainBuildResponse\x12^\n\x0f\x42undleArtifacts\x12$.chromite.api.BundleToolchainRequest\x1a%.chromite.api.BundleToolchainResponse\x12^\n\x0fGetUpdatedFiles\x12$.chromite.api.GetUpdatedFilesRequest\x1a%.chromite.api.GetUpdatedFilesResponse\x12S\n\x0eGetClippyLints\x12\x1b.chromite.api.LinterRequest\x1a\x1c.chromite.api.LinterResponse\"\x06\xc2\xed\x1a\x02\x10\x01\x1a\x11\xc2\xed\x1a\r\n\ttoolchain\x10\x02\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
+  serialized_pb=b'\n\x1c\x63hromite/api/toolchain.proto\x12\x0c\x63hromite.api\x1a\x1c\x63hromite/api/artifacts.proto\x1a\x1c\x63hromite/api/build_api.proto\x1a\x1a\x63hromite/api/sysroot.proto\x1a\x1f\x63hromiumos/builder_config.proto\x1a\x17\x63hromiumos/common.proto\"\x83\x01\n\x0c\x41rtifactInfo\x12H\n\rartifact_type\x18\x01 \x01(\x0e\x32\x31.chromiumos.BuilderConfig.Artifacts.ArtifactTypes\x12)\n\tartifacts\x18\x02 \x03(\x0b\x32\x16.chromite.api.Artifact\"\x83\x03\n\x1fPrepareForToolchainBuildRequest\x12I\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x31.chromiumos.BuilderConfig.Artifacts.ArtifactTypes\x12\"\n\x06\x63hroot\x18\x02 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x03 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12N\n\x0finput_artifacts\x18\x04 \x03(\x0b\x32\x35.chromiumos.BuilderConfig.Artifacts.InputArtifactInfo\x12\x42\n\x0f\x61\x64\x64itional_args\x18\x05 \x01(\x0b\x32).chromiumos.PrepareForBuildAdditionalArgs\x12\x35\n\x0cprofile_info\x18\x06 \x01(\x0b\x32\x1f.chromiumos.ArtifactProfileInfo\"q\n PrepareForToolchainBuildResponse\x12M\n\x0f\x62uild_relevance\x18\x01 \x01(\x0e\x32\x34.chromite.api.PrepareForBuildResponse.BuildRelevance\"\xbe\x02\n\x16\x42undleToolchainRequest\x12\"\n\x06\x63hroot\x18\x01 \x01(\x0b\x32\x12.chromiumos.Chroot\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\x12\n\noutput_dir\x18\x03 \x01(\t\x12I\n\x0e\x61rtifact_types\x18\x04 \x03(\x0e\x32\x31.chromiumos.BuilderConfig.Artifacts.ArtifactTypes\x12\x42\n\x0f\x61\x64\x64itional_args\x18\x05 \x01(\x0b\x32).chromiumos.PrepareForBuildAdditionalArgs\x12\x35\n\x0cprofile_info\x18\x06 \x01(\x0b\x32\x1f.chromiumos.ArtifactProfileInfo\"S\n\x17\x42undleToolchainResponse\x12\x32\n\x0e\x61rtifacts_info\x18\x02 \x03(\x0b\x32\x1a.chromite.api.ArtifactInfoJ\x04\x08\x01\x10\x02\"\xeb\x01\n\x16GetUpdatedFilesRequest\x12R\n\x12uploaded_artifacts\x18\x01 \x03(\x0b\x32\x36.chromite.api.GetUpdatedFilesRequest.UploadedArtifacts\x1a}\n\x11UploadedArtifacts\x12\x31\n\rartifact_info\x18\x01 \x01(\x0b\x32\x1a.chromite.api.ArtifactInfo\x12\x35\n\x0cprofile_info\x18\x02 \x01(\x0b\x32\x1f.chromiumos.ArtifactProfileInfo\"\xf4\x03\n\x17GetUpdatedFilesResponse\x12H\n\rupdated_files\x18\x01 \x03(\x0b\x32\x31.chromite.api.GetUpdatedFilesResponse.UpdatedFile\x12\x16\n\x0e\x63ommit_message\x18\x02 \x01(\t\x12I\n\rcommit_footer\x18\x03 \x03(\x0b\x32\x32.chromite.api.GetUpdatedFilesResponse.CommitFooter\x1a\x1b\n\x0bUpdatedFile\x12\x0c\n\x04path\x18\x01 \x01(\t\x1a\x41\n\x0e\x43qDependFooter\x12/\n\rgerrit_change\x18\x01 \x03(\x0b\x32\x18.chromiumos.GerritChange\x1a\x1c\n\rCqClTagFooter\x12\x0b\n\x03tag\x18\x01 \x01(\t\x1a\xad\x01\n\x0c\x43ommitFooter\x12I\n\tcq_depend\x18\x01 \x01(\x0b\x32\x34.chromite.api.GetUpdatedFilesResponse.CqDependFooterH\x00\x12H\n\tcq_cl_tag\x18\x02 \x01(\x0b\x32\x33.chromite.api.GetUpdatedFilesResponse.CqClTagFooterH\x00\x42\x08\n\x06\x66ooter\"\xd2\x01\n\rLinterFinding\x12\x0f\n\x07message\x18\x01 \x01(\t\x12\x36\n\tlocations\x18\x02 \x03(\x0b\x32#.chromite.api.LinterFindingLocation\x12\x33\n\x06linter\x18\x03 \x01(\x0e\x32#.chromite.api.LinterFinding.Linters\"C\n\x07Linters\x12\x16\n\x12LINTER_UNSPECIFIED\x10\x00\x12\x0e\n\nCLANG_TIDY\x10\x01\x12\x10\n\x0c\x43\x41RGO_CLIPPY\x10\x02\"O\n\x15LinterFindingLocation\x12\x10\n\x08\x66ilepath\x18\x01 \x01(\t\x12\x12\n\nline_start\x18\x02 \x01(\x05\x12\x10\n\x08line_end\x18\x03 \x01(\x05\"\x86\x01\n\rLinterRequest\x12)\n\x08packages\x18\x01 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12&\n\x07sysroot\x18\x02 \x01(\x0b\x32\x15.chromite.api.Sysroot\x12\"\n\x06\x63hroot\x18\x03 \x01(\x0b\x32\x12.chromiumos.Chroot\"?\n\x0eLinterResponse\x12-\n\x08\x66indings\x18\x01 \x03(\x0b\x32\x1b.chromite.api.LinterFinding2\x84\x04\n\x10ToolchainService\x12p\n\x0fPrepareForBuild\x12-.chromite.api.PrepareForToolchainBuildRequest\x1a..chromite.api.PrepareForToolchainBuildResponse\x12^\n\x0f\x42undleArtifacts\x12$.chromite.api.BundleToolchainRequest\x1a%.chromite.api.BundleToolchainResponse\x12^\n\x0fGetUpdatedFiles\x12$.chromite.api.GetUpdatedFilesRequest\x1a%.chromite.api.GetUpdatedFilesResponse\x12V\n\x11\x45mergeWithLinting\x12\x1b.chromite.api.LinterRequest\x1a\x1c.chromite.api.LinterResponse\"\x06\xc2\xed\x1a\x02\x10\x01\x12S\n\x0eGetClippyLints\x12\x1b.chromite.api.LinterRequest\x1a\x1c.chromite.api.LinterResponse\"\x06\xc2\xed\x1a\x02\x10\x01\x1a\x11\xc2\xed\x1a\r\n\ttoolchain\x10\x02\x42\x38Z6go.chromium.org/chromiumos/infra/proto/go/chromite/apib\x06proto3'
   ,
   dependencies=[chromite_dot_api_dot_artifacts__pb2.DESCRIPTOR,chromite_dot_api_dot_build__api__pb2.DESCRIPTOR,chromite_dot_api_dot_sysroot__pb2.DESCRIPTOR,chromiumos_dot_builder__config__pb2.DESCRIPTOR,chromiumos_dot_common__pb2.DESCRIPTOR,])
 
-_AFDOARTIFACTTYPE = _descriptor.EnumDescriptor(
-  name='AFDOArtifactType',
-  full_name='chromite.api.AFDOArtifactType',
+
+
+_LINTERFINDING_LINTERS = _descriptor.EnumDescriptor(
+  name='Linters',
+  full_name='chromite.api.LinterFinding.Linters',
   filename=None,
   file=DESCRIPTOR,
   values=[
     _descriptor.EnumValueDescriptor(
-      name='NONE_TYPE', index=0, number=0,
+      name='LINTER_UNSPECIFIED', index=0, number=0,
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='ORDERFILE', index=1, number=1,
+      name='CLANG_TIDY', index=1, number=1,
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='BENCHMARK_AFDO', index=2, number=2,
-      serialized_options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='KERNEL_AFDO', index=3, number=3,
-      serialized_options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='CHROME_AFDO', index=4, number=4,
+      name='CARGO_CLIPPY', index=2, number=2,
       serialized_options=None,
       type=None),
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2529,
-  serialized_end=2631,
+  serialized_start=2122,
+  serialized_end=2189,
 )
-_sym_db.RegisterEnumDescriptor(_AFDOARTIFACTTYPE)
-
-AFDOArtifactType = enum_type_wrapper.EnumTypeWrapper(_AFDOARTIFACTTYPE)
-NONE_TYPE = 0
-ORDERFILE = 1
-BENCHMARK_AFDO = 2
-KERNEL_AFDO = 3
-CHROME_AFDO = 4
-
+_sym_db.RegisterEnumDescriptor(_LINTERFINDING_LINTERS)
 
 
 _ARTIFACTINFO = _descriptor.Descriptor(
@@ -546,75 +531,6 @@
 )
 
 
-_VERIFYAFDOARTIFACTSREQUEST = _descriptor.Descriptor(
-  name='VerifyAFDOArtifactsRequest',
-  full_name='chromite.api.VerifyAFDOArtifactsRequest',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='build_target', full_name='chromite.api.VerifyAFDOArtifactsRequest.build_target', index=0,
-      number=1, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='artifact_type', full_name='chromite.api.VerifyAFDOArtifactsRequest.artifact_type', index=1,
-      number=2, type=14, cpp_type=8, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1979,
-  serialized_end=2107,
-)
-
-
-_VERIFYAFDOARTIFACTSRESPONSE = _descriptor.Descriptor(
-  name='VerifyAFDOArtifactsResponse',
-  full_name='chromite.api.VerifyAFDOArtifactsResponse',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='status', full_name='chromite.api.VerifyAFDOArtifactsResponse.status', index=0,
-      number=1, type=8, cpp_type=7, label=1,
-      has_default_value=False, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=2109,
-  serialized_end=2154,
-)
-
-
 _LINTERFINDING = _descriptor.Descriptor(
   name='LinterFinding',
   full_name='chromite.api.LinterFinding',
@@ -636,11 +552,19 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='linter', full_name='chromite.api.LinterFinding.linter', index=2,
+      number=3, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
   nested_types=[],
   enum_types=[
+    _LINTERFINDING_LINTERS,
   ],
   serialized_options=None,
   is_extendable=False,
@@ -648,8 +572,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2156,
-  serialized_end=2244,
+  serialized_start=1979,
+  serialized_end=2189,
 )
 
 
@@ -693,8 +617,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2246,
-  serialized_end=2325,
+  serialized_start=2191,
+  serialized_end=2270,
 )
 
 
@@ -738,8 +662,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2328,
-  serialized_end=2462,
+  serialized_start=2273,
+  serialized_end=2407,
 )
 
 
@@ -769,8 +693,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2464,
-  serialized_end=2527,
+  serialized_start=2409,
+  serialized_end=2472,
 )
 
 _ARTIFACTINFO.fields_by_name['artifact_type'].enum_type = chromiumos_dot_builder__config__pb2._BUILDERCONFIG_ARTIFACTS_ARTIFACTTYPES
@@ -807,9 +731,9 @@
 _GETUPDATEDFILESRESPONSE_COMMITFOOTER.fields_by_name['cq_cl_tag'].containing_oneof = _GETUPDATEDFILESRESPONSE_COMMITFOOTER.oneofs_by_name['footer']
 _GETUPDATEDFILESRESPONSE.fields_by_name['updated_files'].message_type = _GETUPDATEDFILESRESPONSE_UPDATEDFILE
 _GETUPDATEDFILESRESPONSE.fields_by_name['commit_footer'].message_type = _GETUPDATEDFILESRESPONSE_COMMITFOOTER
-_VERIFYAFDOARTIFACTSREQUEST.fields_by_name['build_target'].message_type = chromiumos_dot_common__pb2._BUILDTARGET
-_VERIFYAFDOARTIFACTSREQUEST.fields_by_name['artifact_type'].enum_type = chromiumos_dot_common__pb2._AFDOARTIFACTTYPE
 _LINTERFINDING.fields_by_name['locations'].message_type = _LINTERFINDINGLOCATION
+_LINTERFINDING.fields_by_name['linter'].enum_type = _LINTERFINDING_LINTERS
+_LINTERFINDING_LINTERS.containing_type = _LINTERFINDING
 _LINTERREQUEST.fields_by_name['packages'].message_type = chromiumos_dot_common__pb2._PACKAGEINFO
 _LINTERREQUEST.fields_by_name['sysroot'].message_type = chromite_dot_api_dot_sysroot__pb2._SYSROOT
 _LINTERREQUEST.fields_by_name['chroot'].message_type = chromiumos_dot_common__pb2._CHROOT
@@ -821,13 +745,10 @@
 DESCRIPTOR.message_types_by_name['BundleToolchainResponse'] = _BUNDLETOOLCHAINRESPONSE
 DESCRIPTOR.message_types_by_name['GetUpdatedFilesRequest'] = _GETUPDATEDFILESREQUEST
 DESCRIPTOR.message_types_by_name['GetUpdatedFilesResponse'] = _GETUPDATEDFILESRESPONSE
-DESCRIPTOR.message_types_by_name['VerifyAFDOArtifactsRequest'] = _VERIFYAFDOARTIFACTSREQUEST
-DESCRIPTOR.message_types_by_name['VerifyAFDOArtifactsResponse'] = _VERIFYAFDOARTIFACTSRESPONSE
 DESCRIPTOR.message_types_by_name['LinterFinding'] = _LINTERFINDING
 DESCRIPTOR.message_types_by_name['LinterFindingLocation'] = _LINTERFINDINGLOCATION
 DESCRIPTOR.message_types_by_name['LinterRequest'] = _LINTERREQUEST
 DESCRIPTOR.message_types_by_name['LinterResponse'] = _LINTERRESPONSE
-DESCRIPTOR.enum_types_by_name['AFDOArtifactType'] = _AFDOARTIFACTTYPE
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
 ArtifactInfo = _reflection.GeneratedProtocolMessageType('ArtifactInfo', (_message.Message,), {
@@ -919,20 +840,6 @@
 _sym_db.RegisterMessage(GetUpdatedFilesResponse.CqClTagFooter)
 _sym_db.RegisterMessage(GetUpdatedFilesResponse.CommitFooter)
 
-VerifyAFDOArtifactsRequest = _reflection.GeneratedProtocolMessageType('VerifyAFDOArtifactsRequest', (_message.Message,), {
-  'DESCRIPTOR' : _VERIFYAFDOARTIFACTSREQUEST,
-  '__module__' : 'chromite.api.toolchain_pb2'
-  # @@protoc_insertion_point(class_scope:chromite.api.VerifyAFDOArtifactsRequest)
-  })
-_sym_db.RegisterMessage(VerifyAFDOArtifactsRequest)
-
-VerifyAFDOArtifactsResponse = _reflection.GeneratedProtocolMessageType('VerifyAFDOArtifactsResponse', (_message.Message,), {
-  'DESCRIPTOR' : _VERIFYAFDOARTIFACTSRESPONSE,
-  '__module__' : 'chromite.api.toolchain_pb2'
-  # @@protoc_insertion_point(class_scope:chromite.api.VerifyAFDOArtifactsResponse)
-  })
-_sym_db.RegisterMessage(VerifyAFDOArtifactsResponse)
-
 LinterFinding = _reflection.GeneratedProtocolMessageType('LinterFinding', (_message.Message,), {
   'DESCRIPTOR' : _LINTERFINDING,
   '__module__' : 'chromite.api.toolchain_pb2'
@@ -970,31 +877,13 @@
   file=DESCRIPTOR,
   index=0,
   serialized_options=b'\302\355\032\r\n\ttoolchain\020\002',
-  serialized_start=2634,
-  serialized_end=3310,
+  serialized_start=2475,
+  serialized_end=2991,
   methods=[
   _descriptor.MethodDescriptor(
-    name='UpdateEbuildWithAFDOArtifacts',
-    full_name='chromite.api.ToolchainService.UpdateEbuildWithAFDOArtifacts',
-    index=0,
-    containing_service=None,
-    input_type=_VERIFYAFDOARTIFACTSREQUEST,
-    output_type=_VERIFYAFDOARTIFACTSRESPONSE,
-    serialized_options=b'\302\355\032\002\020\001',
-  ),
-  _descriptor.MethodDescriptor(
-    name='UploadVettedAFDOArtifacts',
-    full_name='chromite.api.ToolchainService.UploadVettedAFDOArtifacts',
-    index=1,
-    containing_service=None,
-    input_type=_VERIFYAFDOARTIFACTSREQUEST,
-    output_type=_VERIFYAFDOARTIFACTSRESPONSE,
-    serialized_options=b'\302\355\032\002\020\001',
-  ),
-  _descriptor.MethodDescriptor(
     name='PrepareForBuild',
     full_name='chromite.api.ToolchainService.PrepareForBuild',
-    index=2,
+    index=0,
     containing_service=None,
     input_type=_PREPAREFORTOOLCHAINBUILDREQUEST,
     output_type=_PREPAREFORTOOLCHAINBUILDRESPONSE,
@@ -1003,7 +892,7 @@
   _descriptor.MethodDescriptor(
     name='BundleArtifacts',
     full_name='chromite.api.ToolchainService.BundleArtifacts',
-    index=3,
+    index=1,
     containing_service=None,
     input_type=_BUNDLETOOLCHAINREQUEST,
     output_type=_BUNDLETOOLCHAINRESPONSE,
@@ -1012,16 +901,25 @@
   _descriptor.MethodDescriptor(
     name='GetUpdatedFiles',
     full_name='chromite.api.ToolchainService.GetUpdatedFiles',
-    index=4,
+    index=2,
     containing_service=None,
     input_type=_GETUPDATEDFILESREQUEST,
     output_type=_GETUPDATEDFILESRESPONSE,
     serialized_options=None,
   ),
   _descriptor.MethodDescriptor(
+    name='EmergeWithLinting',
+    full_name='chromite.api.ToolchainService.EmergeWithLinting',
+    index=3,
+    containing_service=None,
+    input_type=_LINTERREQUEST,
+    output_type=_LINTERRESPONSE,
+    serialized_options=b'\302\355\032\002\020\001',
+  ),
+  _descriptor.MethodDescriptor(
     name='GetClippyLints',
     full_name='chromite.api.ToolchainService.GetClippyLints',
-    index=5,
+    index=4,
     containing_service=None,
     input_type=_LINTERREQUEST,
     output_type=_LINTERRESPONSE,
diff --git a/api/gen_sdk/chromiumos/build_report_pb2.py b/api/gen_sdk/chromiumos/build_report_pb2.py
index c727ac5..38ae259 100644
--- a/api/gen_sdk/chromiumos/build_report_pb2.py
+++ b/api/gen_sdk/chromiumos/build_report_pb2.py
@@ -20,7 +20,7 @@
   package='chromiumos',
   syntax='proto3',
   serialized_options=b'\n!com.google.chrome.crosinfra.protoZ4go.chromium.org/chromiumos/infra/proto/go/chromiumos',
-  serialized_pb=b'\n\x1d\x63hromiumos/build_report.proto\x12\nchromiumos\x1a\x17\x63hromiumos/common.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"_\n\tTimeframe\x12)\n\x05\x62\x65gin\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\'\n\x03\x65nd\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"\xd7\x12\n\x0f\x42uildReportBeta\x12\x18\n\x0e\x62uildbucket_id\x18\x01 \x01(\x03H\x00\x12\x33\n\x04type\x18\x02 \x01(\x0e\x32%.chromiumos.BuildReportBeta.BuildType\x12\x37\n\x06status\x18\x03 \x01(\x0b\x32\'.chromiumos.BuildReportBeta.BuildStatus\x12\x37\n\x06\x63onfig\x18\x04 \x01(\x0b\x32\'.chromiumos.BuildReportBeta.BuildConfig\x12\x36\n\x05steps\x18\x05 \x01(\x0b\x32\'.chromiumos.BuildReportBeta.StepDetails\x12<\n\tartifacts\x18\x07 \x03(\x0b\x32).chromiumos.BuildReportBeta.BuildArtifact\x1a\xf0\x01\n\x0b\x42uildStatus\x12=\n\x05value\x18\x01 \x01(\x0e\x32..chromiumos.BuildReportBeta.BuildStatus.Status\"\xa1\x01\n\x06Status\x12\r\n\tUNDEFINED\x10\x00\x12\x11\n\rKIND_TERMINAL\x10\x01\x12\x10\n\x0cKIND_RUNNING\x10\x02\x12\x0b\n\x07SUCCESS\x10\x64\x12\x0b\n\x07\x46\x41ILURE\x10\x65\x12\x11\n\rINFRA_FAILURE\x10\x66\x12\x0c\n\x08WATCHDOG\x10g\x12\x0c\n\x08\x43\x41NCELED\x10h\x12\x0c\n\x07RUNNING\x10\xc8\x01\x12\x0c\n\x07WAITING\x10\xc9\x01\x1a\xd1\x02\n\x0b\x42uildConfig\x12>\n\x06\x62ranch\x18\x01 \x01(\x0b\x32..chromiumos.BuildReportBeta.BuildConfig.Branch\x12@\n\x07release\x18\x02 \x01(\x0b\x32/.chromiumos.BuildReportBeta.BuildConfig.Release\x12=\n\x06models\x18\x03 \x03(\x0b\x32-.chromiumos.BuildReportBeta.BuildConfig.Model\x1a\x15\n\x05Model\x12\x0c\n\x04name\x18\x01 \x01(\t\x1aR\n\x07Release\x12\x11\n\tmilestone\x18\x01 \x01(\x05\x12\r\n\x05\x62uild\x18\x02 \x01(\t\x12%\n\x08\x63hannels\x18\x03 \x03(\x0e\x32\x13.chromiumos.Channel\x1a\x16\n\x06\x42ranch\x12\x0c\n\x04name\x18\x01 \x01(\t\x1a\xb5\x04\n\rBuildArtifact\x12<\n\x04type\x18\x01 \x01(\x0e\x32..chromiumos.BuildReportBeta.BuildArtifact.Type\x12:\n\x03uri\x18\x02 \x01(\x0b\x32-.chromiumos.BuildReportBeta.BuildArtifact.URI\x12\x0e\n\x06sha256\x18\x03 \x01(\t\x12+\n\x07\x63reated\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x1a\x1b\n\x03URI\x12\r\n\x03gcs\x18\x01 \x01(\tH\x00\x42\x05\n\x03uri\"\xcf\x02\n\x04Type\x12\r\n\tUNDEFINED\x10\x00\x12\x0f\n\x0bIMAGE_TYPES\x10\x01\x12\x12\n\x0e\x46IRMWARE_TYPES\x10\x02\x12\x0e\n\nAFDO_TYPES\x10\x03\x12\x11\n\rRELEASE_IMAGE\x10\x64\x12\x12\n\x0eRECOVERY_IMAGE\x10\x65\x12\r\n\tDLC_IMAGE\x10\x66\x12\x16\n\x12\x44\x45\x42UG_SYMBOL_IMAGE\x10g\x12\x10\n\x0cHWQUAL_IMAGE\x10h\x12\x0e\n\nTEST_IMAGE\x10i\x12\x15\n\x10\x46IRMWARE_TARBALL\x10\xc8\x01\x12\x1a\n\x15\x46IRMWARE_TARBALL_INFO\x10\xc9\x01\x12\x12\n\rFIRMWARE_LCOV\x10\xca\x01\x12\x13\n\x0e\x41\x46\x44O_ORDERFILE\x10\xac\x02\x12\x13\n\x0e\x41\x46\x44O_BENCHMARK\x10\xad\x02\x12\x10\n\x0b\x41\x46\x44O_KERNEL\x10\xae\x02\x12\x10\n\x0b\x41\x46\x44O_CHROME\x10\xaf\x02\x1a\x97\x06\n\x0bStepDetails\x12\x41\n\x07\x63urrent\x18\x01 \x01(\x0e\x32\x30.chromiumos.BuildReportBeta.StepDetails.StepName\x12?\n\x04info\x18\x02 \x03(\x0b\x32\x31.chromiumos.BuildReportBeta.StepDetails.InfoEntry\x1a\x81\x01\n\x08StepInfo\x12\r\n\x05order\x18\x01 \x01(\x05\x12>\n\x06status\x18\x02 \x01(\x0e\x32..chromiumos.BuildReportBeta.StepDetails.Status\x12&\n\x07runtime\x18\x03 \x01(\x0b\x32\x15.chromiumos.Timeframe\x1a]\n\tInfoEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12?\n\x05value\x18\x02 \x01(\x0b\x32\x30.chromiumos.BuildReportBeta.StepDetails.StepInfo:\x02\x38\x01\"\xc9\x01\n\x06Status\x12\x19\n\x15STEP_STATUS_UNDEFINED\x10\x00\x12\x11\n\rKIND_TERMINAL\x10\x01\x12\x10\n\x0cKIND_RUNNING\x10\x02\x12\x12\n\x0eSTATUS_SUCCESS\x10\x64\x12\x12\n\x0eSTATUS_FAILURE\x10\x65\x12\x18\n\x14STATUS_INFRA_FAILURE\x10\x66\x12\x13\n\x0fSTATUS_WATCHDOG\x10g\x12\x13\n\x0fSTATUS_CANCELED\x10h\x12\x13\n\x0eSTATUS_RUNNING\x10\xc8\x01\"\xd4\x01\n\x08StepName\x12\x12\n\x0eSTEP_UNDEFINED\x10\x00\x12\x10\n\x0cSTEP_OVERALL\x10\x64\x12\x0e\n\tSTEP_SYNC\x10\xc8\x01\x12\x15\n\x10STEP_SYNC_CHROME\x10\xc9\x01\x12\r\n\x08STEP_SDK\x10\xac\x02\x12\x12\n\rSTEP_SDK_INIT\x10\xad\x02\x12\x14\n\x0fSTEP_SDK_UPDATE\x10\xae\x02\x12\x0f\n\nSTEP_BUILD\x10\x90\x03\x12\x17\n\x12STEP_BUILD_SYSROOT\x10\x91\x03\x12\x18\n\x13STEP_BUILD_PACKAGES\x10\x92\x03\"n\n\tBuildType\x12\x18\n\x14\x42UILD_TYPE_UNDEFINED\x10\x00\x12\x16\n\x12\x42UILD_TYPE_RELEASE\x10\x01\x12\x17\n\x13\x42UILD_TYPE_FIRMWARE\x10\x02\x12\x16\n\x12\x42UILD_TYPE_FACTORY\x10\x03\x42\x04\n\x02idBY\n!com.google.chrome.crosinfra.protoZ4go.chromium.org/chromiumos/infra/proto/go/chromiumosb\x06proto3'
+  serialized_pb=b'\n\x1d\x63hromiumos/build_report.proto\x12\nchromiumos\x1a\x17\x63hromiumos/common.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"_\n\tTimeframe\x12)\n\x05\x62\x65gin\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\'\n\x03\x65nd\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\")\n\x07\x42uildId\x12\x18\n\x0e\x62uildbucket_id\x18\x01 \x01(\x03H\x00\x42\x04\n\x02id\"\xd2)\n\x0f\x42uildReportBeta\x12\x18\n\x0e\x62uildbucket_id\x18\x01 \x01(\x03H\x00\x12\r\n\x05\x63ount\x18\x08 \x01(\x03\x12#\n\x06parent\x18\t \x01(\x0b\x32\x13.chromiumos.BuildId\x12%\n\x08\x63hildren\x18\n \x03(\x0b\x32\x13.chromiumos.BuildId\x12\x33\n\x04type\x18\x02 \x01(\x0e\x32%.chromiumos.BuildReportBeta.BuildType\x12\x37\n\x06status\x18\x03 \x01(\x0b\x32\'.chromiumos.BuildReportBeta.BuildStatus\x12\x37\n\x06\x63onfig\x18\x04 \x01(\x0b\x32\'.chromiumos.BuildReportBeta.BuildConfig\x12\x36\n\x05steps\x18\x05 \x01(\x0b\x32\'.chromiumos.BuildReportBeta.StepDetails\x12\x46\n\rsigned_builds\x18\x06 \x03(\x0b\x32/.chromiumos.BuildReportBeta.SignedBuildMetadata\x12\x35\n\x08payloads\x18\x0b \x03(\x0b\x32#.chromiumos.BuildReportBeta.Payload\x12<\n\tartifacts\x18\x07 \x03(\x0b\x32).chromiumos.BuildReportBeta.BuildArtifact\x1a\xf0\x01\n\x0b\x42uildStatus\x12=\n\x05value\x18\x01 \x01(\x0e\x32..chromiumos.BuildReportBeta.BuildStatus.Status\"\xa1\x01\n\x06Status\x12\r\n\tUNDEFINED\x10\x00\x12\x11\n\rKIND_TERMINAL\x10\x01\x12\x10\n\x0cKIND_RUNNING\x10\x02\x12\x0b\n\x07SUCCESS\x10\x64\x12\x0b\n\x07\x46\x41ILURE\x10\x65\x12\x11\n\rINFRA_FAILURE\x10\x66\x12\x0c\n\x08WATCHDOG\x10g\x12\x0c\n\x08\x43\x41NCELED\x10h\x12\x0c\n\x07RUNNING\x10\xc8\x01\x12\x0c\n\x07WAITING\x10\xc9\x01\x1a\xb7\x0b\n\x0b\x42uildConfig\x12>\n\x06\x62ranch\x18\x01 \x01(\x0b\x32..chromiumos.BuildReportBeta.BuildConfig.Branch\x12P\n\x18\x61ndroid_container_branch\x18\x02 \x01(\x0b\x32..chromiumos.BuildReportBeta.BuildConfig.Branch\x12>\n\x06target\x18\x03 \x01(\x0b\x32..chromiumos.BuildReportBeta.BuildConfig.Target\x12P\n\x18\x61ndroid_container_target\x18\x04 \x01(\x0b\x32..chromiumos.BuildReportBeta.BuildConfig.Target\x12@\n\x07release\x18\x05 \x01(\x0b\x32/.chromiumos.BuildReportBeta.BuildConfig.Release\x12\x41\n\x08versions\x18\x06 \x03(\x0b\x32/.chromiumos.BuildReportBeta.BuildConfig.Version\x12\x13\n\x0b\x61rc_use_set\x18\x07 \x01(\x08\x12=\n\x06models\x18\x08 \x03(\x0b\x32-.chromiumos.BuildReportBeta.BuildConfig.Model\x1a\xa3\x03\n\x05Model\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x17\n\x0f\x66irmware_key_id\x18\x02 \x01(\t\x12L\n\x08versions\x18\x03 \x03(\x0b\x32:.chromiumos.BuildReportBeta.BuildConfig.Model.ModelVersion\x1ak\n\x0cModelVersion\x12L\n\x04kind\x18\x01 \x01(\x0e\x32>.chromiumos.BuildReportBeta.BuildConfig.Model.ModelVersionKind\x12\r\n\x05value\x18\x02 \x01(\t\"\xb7\x01\n\x10ModelVersionKind\x12 \n\x1cMODEL_VERSION_KIND_UNDEFINED\x10\x00\x12\"\n\x1eMODEL_VERSION_KIND_EC_FIRMWARE\x10\x01\x12-\n)MODEL_VERSION_KIND_MAIN_READONLY_FIRMWARE\x10\x02\x12.\n*MODEL_VERSION_KIND_MAIN_READWRITE_FIRMWARE\x10\x03\x1a\x30\n\x07Release\x12%\n\x08\x63hannels\x18\x01 \x03(\x0e\x32\x13.chromiumos.Channel\x1a\x16\n\x06\x42ranch\x12\x0c\n\x04name\x18\x01 \x01(\t\x1a[\n\x07Version\x12\x41\n\x04kind\x18\x01 \x01(\x0e\x32\x33.chromiumos.BuildReportBeta.BuildConfig.VersionKind\x12\r\n\x05value\x18\x02 \x01(\t\x1a\x16\n\x06Target\x12\x0c\n\x04name\x18\x01 \x01(\t\"\xc5\x02\n\x0bVersionKind\x12\x1a\n\x16VERSION_KIND_UNDEFINED\x10\x00\x12\x1b\n\x17VERSION_KIND_ASH_CHROME\x10\x01\x12\x17\n\x13VERSION_KIND_CHROME\x10\x02\x12\x14\n\x10VERSION_KIND_ARC\x10\x03\x12\x19\n\x15VERSION_KIND_PLATFORM\x10\x04\x12\x1a\n\x16VERSION_KIND_MILESTONE\x10\x05\x12\"\n\x1eVERSION_KIND_ANDROID_CONTAINER\x10\x06\x12\x1c\n\x18VERSION_KIND_EC_FIRMWARE\x10\x07\x12\x1c\n\x18VERSION_KIND_FINGERPRINT\x10\x08\x12\x17\n\x13VERSION_KIND_KERNEL\x10\t\x12\x1e\n\x1aVERSION_KIND_MAIN_FIRMWARE\x10\n\x1a\xef\x04\n\rBuildArtifact\x12<\n\x04type\x18\x01 \x01(\x0e\x32..chromiumos.BuildReportBeta.BuildArtifact.Type\x12:\n\x03uri\x18\x02 \x01(\x0b\x32-.chromiumos.BuildReportBeta.BuildArtifact.URI\x12\x0e\n\x06sha256\x18\x03 \x01(\t\x12+\n\x07\x63reated\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x1a\x1b\n\x03URI\x12\r\n\x03gcs\x18\x01 \x01(\tH\x00\x42\x05\n\x03uri\"\x89\x03\n\x04Type\x12\r\n\tUNDEFINED\x10\x00\x12\x0f\n\x0bIMAGE_TYPES\x10\x01\x12\x12\n\x0e\x46IRMWARE_TYPES\x10\x02\x12\x0e\n\nAFDO_TYPES\x10\x03\x12\x11\n\rPAYLOAD_TYPES\x10\x04\x12\x11\n\rRELEASE_IMAGE\x10\x64\x12\x12\n\x0eRECOVERY_IMAGE\x10\x65\x12\r\n\tDLC_IMAGE\x10\x66\x12\x16\n\x12\x44\x45\x42UG_SYMBOL_IMAGE\x10g\x12\x10\n\x0cHWQUAL_IMAGE\x10h\x12\x0e\n\nTEST_IMAGE\x10i\x12\x15\n\x10\x46IRMWARE_TARBALL\x10\xc8\x01\x12\x1a\n\x15\x46IRMWARE_TARBALL_INFO\x10\xc9\x01\x12\x12\n\rFIRMWARE_LCOV\x10\xca\x01\x12\x13\n\x0e\x41\x46\x44O_ORDERFILE\x10\xac\x02\x12\x13\n\x0e\x41\x46\x44O_BENCHMARK\x10\xad\x02\x12\x10\n\x0b\x41\x46\x44O_KERNEL\x10\xae\x02\x12\x10\n\x0b\x41\x46\x44O_CHROME\x10\xaf\x02\x12\x11\n\x0cPAYLOAD_FULL\x10\x90\x03\x12\x12\n\rPAYLOAD_DELTA\x10\x91\x03\x1a\xc6\x06\n\x0bStepDetails\x12\x41\n\x07\x63urrent\x18\x01 \x01(\x0e\x32\x30.chromiumos.BuildReportBeta.StepDetails.StepName\x12?\n\x04info\x18\x02 \x03(\x0b\x32\x31.chromiumos.BuildReportBeta.StepDetails.InfoEntry\x1a\x81\x01\n\x08StepInfo\x12\r\n\x05order\x18\x01 \x01(\x05\x12>\n\x06status\x18\x02 \x01(\x0e\x32..chromiumos.BuildReportBeta.StepDetails.Status\x12&\n\x07runtime\x18\x03 \x01(\x0b\x32\x15.chromiumos.Timeframe\x1a]\n\tInfoEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12?\n\x05value\x18\x02 \x01(\x0b\x32\x30.chromiumos.BuildReportBeta.StepDetails.StepInfo:\x02\x38\x01\"\xc9\x01\n\x06Status\x12\x19\n\x15STEP_STATUS_UNDEFINED\x10\x00\x12\x11\n\rKIND_TERMINAL\x10\x01\x12\x10\n\x0cKIND_RUNNING\x10\x02\x12\x12\n\x0eSTATUS_SUCCESS\x10\x64\x12\x12\n\x0eSTATUS_FAILURE\x10\x65\x12\x18\n\x14STATUS_INFRA_FAILURE\x10\x66\x12\x13\n\x0fSTATUS_WATCHDOG\x10g\x12\x13\n\x0fSTATUS_CANCELED\x10h\x12\x13\n\x0eSTATUS_RUNNING\x10\xc8\x01\"\x83\x02\n\x08StepName\x12\x12\n\x0eSTEP_UNDEFINED\x10\x00\x12\x10\n\x0cSTEP_OVERALL\x10\x64\x12\x0e\n\tSTEP_SYNC\x10\xc8\x01\x12\x15\n\x10STEP_SYNC_CHROME\x10\xc9\x01\x12\r\n\x08STEP_SDK\x10\xac\x02\x12\x12\n\rSTEP_SDK_INIT\x10\xad\x02\x12\x14\n\x0fSTEP_SDK_UPDATE\x10\xae\x02\x12\x0f\n\nSTEP_BUILD\x10\x90\x03\x12\x17\n\x12STEP_BUILD_SYSROOT\x10\x91\x03\x12\x18\n\x13STEP_BUILD_PACKAGES\x10\x92\x03\x12\x17\n\x12STEP_DEBUG_SYMBOLS\x10\xf4\x03\x12\x14\n\x0fSTEP_UNIT_TESTS\x10\xf5\x03\x1a\x98\x08\n\x13SignedBuildMetadata\x12M\n\x06status\x18\x01 \x01(\x0e\x32=.chromiumos.BuildReportBeta.SignedBuildMetadata.SigningStatus\x12\r\n\x05\x62oard\x18\x02 \x01(\t\x12#\n\x04type\x18\x03 \x01(\x0e\x32\x15.chromiumos.ImageType\x12$\n\x07\x63hannel\x18\x04 \x01(\x0e\x32\x13.chromiumos.Channel\x12\x0e\n\x06keyset\x18\x05 \x01(\t\x12\x14\n\x0ckeyset_is_mp\x18\x06 \x01(\x08\x12M\n\x05\x66iles\x18\x07 \x03(\x0b\x32>.chromiumos.BuildReportBeta.SignedBuildMetadata.FileWithHashes\x12I\n\x08versions\x18\x08 \x03(\x0b\x32\x37.chromiumos.BuildReportBeta.SignedBuildMetadata.Version\x1a[\n\x0e\x46ileWithHashes\x12\x10\n\x08\x66ilename\x18\x01 \x01(\t\x12\x0b\n\x03md5\x18\x02 \x01(\t\x12\x0c\n\x04sha1\x18\x03 \x01(\t\x12\x0e\n\x06sha256\x18\x04 \x01(\t\x12\x0c\n\x04size\x18\x05 \x01(\x03\x1a\x63\n\x07Version\x12I\n\x04kind\x18\x01 \x01(\x0e\x32;.chromiumos.BuildReportBeta.SignedBuildMetadata.VersionKind\x12\r\n\x05value\x18\x02 \x01(\t\"\xe0\x01\n\x0bVersionKind\x12\x1a\n\x16VERSION_KIND_UNDEFINED\x10\x00\x12\x19\n\x15VERSION_KIND_PLATFORM\x10\x01\x12\x1a\n\x16VERSION_KIND_MILESTONE\x10\x02\x12!\n\x1dVERSION_KIND_KEY_FIRMWARE_KEY\x10\x03\x12\x1d\n\x19VERSION_KIND_KEY_FIRMWARE\x10\x04\x12\x1f\n\x1bVERSION_KIND_KEY_KERNEL_KEY\x10\x05\x12\x1b\n\x17VERSION_KIND_KEY_KERNEL\x10\x06\"\xf2\x01\n\rSigningStatus\x12\x1a\n\x16SIGNING_STATUS_UNKNOWN\x10\x00\x12\x1e\n\x1aSIGNING_STATUS_DOWNLOADING\x10\x01\x12\x1a\n\x16SIGNING_STATUS_SIGNING\x10\x02\x12\x1c\n\x18SIGNING_STATUS_UPLOADING\x10\x03\x12\x1b\n\x17SIGNING_STATUS_FINISHED\x10\x04\x12\x18\n\x14SIGNING_STATUS_RETRY\x10\x05\x12\x19\n\x15SIGNING_STATUS_PASSED\x10\x06\x12\x19\n\x15SIGNING_STATUS_FAILED\x10\x07\x1a\xb4\x03\n\x07Payload\x12:\n\x07payload\x18\x01 \x01(\x0b\x32).chromiumos.BuildReportBeta.BuildArtifact\x12\x45\n\x0cpayload_type\x18\x02 \x01(\x0e\x32/.chromiumos.BuildReportBeta.Payload.PayloadType\x12\r\n\x05\x62oard\x18\x03 \x01(\t\x12$\n\x07\x63hannel\x18\x04 \x01(\x0e\x32\x13.chromiumos.Channel\x12\r\n\x05\x61ppid\x18\x05 \x01(\t\x12\x1a\n\x12metadata_signature\x18\x06 \x01(\t\x12\x15\n\rmetadata_size\x18\x07 \x01(\x03\x12\x16\n\x0esource_version\x18\x08 \x01(\t\x12\x16\n\x0etarget_version\x18\t \x01(\t\x12\x0c\n\x04size\x18\n \x01(\x03\"q\n\x0bPayloadType\x12\x18\n\x14PAYLOAD_TYPE_UNKNOWN\x10\x00\x12\x19\n\x15PAYLOAD_TYPE_STANDARD\x10\x01\x12\x17\n\x13PAYLOAD_TYPE_MINIOS\x10\x02\x12\x14\n\x10PAYLOAD_TYPE_DLC\x10\x03\"n\n\tBuildType\x12\x18\n\x14\x42UILD_TYPE_UNDEFINED\x10\x00\x12\x16\n\x12\x42UILD_TYPE_RELEASE\x10\x01\x12\x17\n\x13\x42UILD_TYPE_FIRMWARE\x10\x02\x12\x16\n\x12\x42UILD_TYPE_FACTORY\x10\x03\x42\x04\n\x02id\"E\n\x0f\x42uildReportList\x12\x32\n\rbuild_reports\x18\x01 \x03(\x0b\x32\x1b.chromiumos.BuildReportBetaBY\n!com.google.chrome.crosinfra.protoZ4go.chromium.org/chromiumos/infra/proto/go/chromiumosb\x06proto3'
   ,
   dependencies=[chromiumos_dot_common__pb2.DESCRIPTOR,google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,])
 
@@ -75,11 +75,99 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=611,
-  serialized_end=772,
+  serialized_start=872,
+  serialized_end=1033,
 )
 _sym_db.RegisterEnumDescriptor(_BUILDREPORTBETA_BUILDSTATUS_STATUS)
 
+_BUILDREPORTBETA_BUILDCONFIG_MODEL_MODELVERSIONKIND = _descriptor.EnumDescriptor(
+  name='ModelVersionKind',
+  full_name='chromiumos.BuildReportBeta.BuildConfig.Model.ModelVersionKind',
+  filename=None,
+  file=DESCRIPTOR,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='MODEL_VERSION_KIND_UNDEFINED', index=0, number=0,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='MODEL_VERSION_KIND_EC_FIRMWARE', index=1, number=1,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='MODEL_VERSION_KIND_MAIN_READONLY_FIRMWARE', index=2, number=2,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='MODEL_VERSION_KIND_MAIN_READWRITE_FIRMWARE', index=3, number=3,
+      serialized_options=None,
+      type=None),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=1797,
+  serialized_end=1980,
+)
+_sym_db.RegisterEnumDescriptor(_BUILDREPORTBETA_BUILDCONFIG_MODEL_MODELVERSIONKIND)
+
+_BUILDREPORTBETA_BUILDCONFIG_VERSIONKIND = _descriptor.EnumDescriptor(
+  name='VersionKind',
+  full_name='chromiumos.BuildReportBeta.BuildConfig.VersionKind',
+  filename=None,
+  file=DESCRIPTOR,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_UNDEFINED', index=0, number=0,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_ASH_CHROME', index=1, number=1,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_CHROME', index=2, number=2,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_ARC', index=3, number=3,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_PLATFORM', index=4, number=4,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_MILESTONE', index=5, number=5,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_ANDROID_CONTAINER', index=6, number=6,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_EC_FIRMWARE', index=7, number=7,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_FINGERPRINT', index=8, number=8,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_KERNEL', index=9, number=9,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_MAIN_FIRMWARE', index=10, number=10,
+      serialized_options=None,
+      type=None),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=2174,
+  serialized_end=2499,
+)
+_sym_db.RegisterEnumDescriptor(_BUILDREPORTBETA_BUILDCONFIG_VERSIONKIND)
+
 _BUILDREPORTBETA_BUILDARTIFACT_TYPE = _descriptor.EnumDescriptor(
   name='Type',
   full_name='chromiumos.BuildReportBeta.BuildArtifact.Type',
@@ -103,62 +191,74 @@
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='RELEASE_IMAGE', index=4, number=100,
+      name='PAYLOAD_TYPES', index=4, number=4,
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='RECOVERY_IMAGE', index=5, number=101,
+      name='RELEASE_IMAGE', index=5, number=100,
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='DLC_IMAGE', index=6, number=102,
+      name='RECOVERY_IMAGE', index=6, number=101,
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='DEBUG_SYMBOL_IMAGE', index=7, number=103,
+      name='DLC_IMAGE', index=7, number=102,
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='HWQUAL_IMAGE', index=8, number=104,
+      name='DEBUG_SYMBOL_IMAGE', index=8, number=103,
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='TEST_IMAGE', index=9, number=105,
+      name='HWQUAL_IMAGE', index=9, number=104,
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='FIRMWARE_TARBALL', index=10, number=200,
+      name='TEST_IMAGE', index=10, number=105,
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='FIRMWARE_TARBALL_INFO', index=11, number=201,
+      name='FIRMWARE_TARBALL', index=11, number=200,
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='FIRMWARE_LCOV', index=12, number=202,
+      name='FIRMWARE_TARBALL_INFO', index=12, number=201,
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='AFDO_ORDERFILE', index=13, number=300,
+      name='FIRMWARE_LCOV', index=13, number=202,
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='AFDO_BENCHMARK', index=14, number=301,
+      name='AFDO_ORDERFILE', index=14, number=300,
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='AFDO_KERNEL', index=15, number=302,
+      name='AFDO_BENCHMARK', index=15, number=301,
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='AFDO_CHROME', index=16, number=303,
+      name='AFDO_KERNEL', index=16, number=302,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='AFDO_CHROME', index=17, number=303,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='PAYLOAD_FULL', index=18, number=400,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='PAYLOAD_DELTA', index=19, number=401,
       serialized_options=None,
       type=None),
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1345,
-  serialized_end=1680,
+  serialized_start=2732,
+  serialized_end=3125,
 )
 _sym_db.RegisterEnumDescriptor(_BUILDREPORTBETA_BUILDARTIFACT_TYPE)
 
@@ -207,8 +307,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2058,
-  serialized_end=2259,
+  serialized_start=3503,
+  serialized_end=3704,
 )
 _sym_db.RegisterEnumDescriptor(_BUILDREPORTBETA_STEPDETAILS_STATUS)
 
@@ -258,14 +358,140 @@
       name='STEP_BUILD_PACKAGES', index=9, number=402,
       serialized_options=None,
       type=None),
+    _descriptor.EnumValueDescriptor(
+      name='STEP_DEBUG_SYMBOLS', index=10, number=500,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='STEP_UNIT_TESTS', index=11, number=501,
+      serialized_options=None,
+      type=None),
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2262,
-  serialized_end=2474,
+  serialized_start=3707,
+  serialized_end=3966,
 )
 _sym_db.RegisterEnumDescriptor(_BUILDREPORTBETA_STEPDETAILS_STEPNAME)
 
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA_VERSIONKIND = _descriptor.EnumDescriptor(
+  name='VersionKind',
+  full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.VersionKind',
+  filename=None,
+  file=DESCRIPTOR,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_UNDEFINED', index=0, number=0,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_PLATFORM', index=1, number=1,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_MILESTONE', index=2, number=2,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_KEY_FIRMWARE_KEY', index=3, number=3,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_KEY_FIRMWARE', index=4, number=4,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_KEY_KERNEL_KEY', index=5, number=5,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='VERSION_KIND_KEY_KERNEL', index=6, number=6,
+      serialized_options=None,
+      type=None),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=4548,
+  serialized_end=4772,
+)
+_sym_db.RegisterEnumDescriptor(_BUILDREPORTBETA_SIGNEDBUILDMETADATA_VERSIONKIND)
+
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA_SIGNINGSTATUS = _descriptor.EnumDescriptor(
+  name='SigningStatus',
+  full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.SigningStatus',
+  filename=None,
+  file=DESCRIPTOR,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='SIGNING_STATUS_UNKNOWN', index=0, number=0,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='SIGNING_STATUS_DOWNLOADING', index=1, number=1,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='SIGNING_STATUS_SIGNING', index=2, number=2,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='SIGNING_STATUS_UPLOADING', index=3, number=3,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='SIGNING_STATUS_FINISHED', index=4, number=4,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='SIGNING_STATUS_RETRY', index=5, number=5,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='SIGNING_STATUS_PASSED', index=6, number=6,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='SIGNING_STATUS_FAILED', index=7, number=7,
+      serialized_options=None,
+      type=None),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=4775,
+  serialized_end=5017,
+)
+_sym_db.RegisterEnumDescriptor(_BUILDREPORTBETA_SIGNEDBUILDMETADATA_SIGNINGSTATUS)
+
+_BUILDREPORTBETA_PAYLOAD_PAYLOADTYPE = _descriptor.EnumDescriptor(
+  name='PayloadType',
+  full_name='chromiumos.BuildReportBeta.Payload.PayloadType',
+  filename=None,
+  file=DESCRIPTOR,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='PAYLOAD_TYPE_UNKNOWN', index=0, number=0,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='PAYLOAD_TYPE_STANDARD', index=1, number=1,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='PAYLOAD_TYPE_MINIOS', index=2, number=2,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='PAYLOAD_TYPE_DLC', index=3, number=3,
+      serialized_options=None,
+      type=None),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=5343,
+  serialized_end=5456,
+)
+_sym_db.RegisterEnumDescriptor(_BUILDREPORTBETA_PAYLOAD_PAYLOADTYPE)
+
 _BUILDREPORTBETA_BUILDTYPE = _descriptor.EnumDescriptor(
   name='BuildType',
   full_name='chromiumos.BuildReportBeta.BuildType',
@@ -291,8 +517,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2476,
-  serialized_end=2586,
+  serialized_start=5458,
+  serialized_end=5568,
 )
 _sym_db.RegisterEnumDescriptor(_BUILDREPORTBETA_BUILDTYPE)
 
@@ -335,6 +561,40 @@
 )
 
 
+_BUILDID = _descriptor.Descriptor(
+  name='BuildId',
+  full_name='chromiumos.BuildId',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='buildbucket_id', full_name='chromiumos.BuildId.buildbucket_id', index=0,
+      number=1, type=3, cpp_type=2, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+    _descriptor.OneofDescriptor(
+      name='id', full_name='chromiumos.BuildId.id',
+      index=0, containing_type=None, fields=[]),
+  ],
+  serialized_start=200,
+  serialized_end=241,
+)
+
+
 _BUILDREPORTBETA_BUILDSTATUS = _descriptor.Descriptor(
   name='BuildStatus',
   full_name='chromiumos.BuildReportBeta.BuildStatus',
@@ -362,8 +622,45 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=532,
-  serialized_end=772,
+  serialized_start=793,
+  serialized_end=1033,
+)
+
+_BUILDREPORTBETA_BUILDCONFIG_MODEL_MODELVERSION = _descriptor.Descriptor(
+  name='ModelVersion',
+  full_name='chromiumos.BuildReportBeta.BuildConfig.Model.ModelVersion',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='kind', full_name='chromiumos.BuildReportBeta.BuildConfig.Model.ModelVersion.kind', index=0,
+      number=1, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='chromiumos.BuildReportBeta.BuildConfig.Model.ModelVersion.value', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1687,
+  serialized_end=1794,
 )
 
 _BUILDREPORTBETA_BUILDCONFIG_MODEL = _descriptor.Descriptor(
@@ -380,11 +677,26 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='firmware_key_id', full_name='chromiumos.BuildReportBeta.BuildConfig.Model.firmware_key_id', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='versions', full_name='chromiumos.BuildReportBeta.BuildConfig.Model.versions', index=2,
+      number=3, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
-  nested_types=[],
+  nested_types=[_BUILDREPORTBETA_BUILDCONFIG_MODEL_MODELVERSION, ],
   enum_types=[
+    _BUILDREPORTBETA_BUILDCONFIG_MODEL_MODELVERSIONKIND,
   ],
   serialized_options=None,
   is_extendable=False,
@@ -392,8 +704,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=983,
-  serialized_end=1004,
+  serialized_start=1561,
+  serialized_end=1980,
 )
 
 _BUILDREPORTBETA_BUILDCONFIG_RELEASE = _descriptor.Descriptor(
@@ -404,22 +716,8 @@
   containing_type=None,
   fields=[
     _descriptor.FieldDescriptor(
-      name='milestone', full_name='chromiumos.BuildReportBeta.BuildConfig.Release.milestone', index=0,
-      number=1, type=5, cpp_type=1, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='build', full_name='chromiumos.BuildReportBeta.BuildConfig.Release.build', index=1,
-      number=2, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=b"".decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='channels', full_name='chromiumos.BuildReportBeta.BuildConfig.Release.channels', index=2,
-      number=3, type=14, cpp_type=8, label=3,
+      name='channels', full_name='chromiumos.BuildReportBeta.BuildConfig.Release.channels', index=0,
+      number=1, type=14, cpp_type=8, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
@@ -436,8 +734,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1006,
-  serialized_end=1088,
+  serialized_start=1982,
+  serialized_end=2030,
 )
 
 _BUILDREPORTBETA_BUILDCONFIG_BRANCH = _descriptor.Descriptor(
@@ -466,8 +764,75 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1090,
-  serialized_end=1112,
+  serialized_start=2032,
+  serialized_end=2054,
+)
+
+_BUILDREPORTBETA_BUILDCONFIG_VERSION = _descriptor.Descriptor(
+  name='Version',
+  full_name='chromiumos.BuildReportBeta.BuildConfig.Version',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='kind', full_name='chromiumos.BuildReportBeta.BuildConfig.Version.kind', index=0,
+      number=1, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='chromiumos.BuildReportBeta.BuildConfig.Version.value', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2056,
+  serialized_end=2147,
+)
+
+_BUILDREPORTBETA_BUILDCONFIG_TARGET = _descriptor.Descriptor(
+  name='Target',
+  full_name='chromiumos.BuildReportBeta.BuildConfig.Target',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='name', full_name='chromiumos.BuildReportBeta.BuildConfig.Target.name', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2149,
+  serialized_end=2171,
 )
 
 _BUILDREPORTBETA_BUILDCONFIG = _descriptor.Descriptor(
@@ -485,15 +850,50 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='release', full_name='chromiumos.BuildReportBeta.BuildConfig.release', index=1,
+      name='android_container_branch', full_name='chromiumos.BuildReportBeta.BuildConfig.android_container_branch', index=1,
       number=2, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='models', full_name='chromiumos.BuildReportBeta.BuildConfig.models', index=2,
-      number=3, type=11, cpp_type=10, label=3,
+      name='target', full_name='chromiumos.BuildReportBeta.BuildConfig.target', index=2,
+      number=3, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='android_container_target', full_name='chromiumos.BuildReportBeta.BuildConfig.android_container_target', index=3,
+      number=4, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='release', full_name='chromiumos.BuildReportBeta.BuildConfig.release', index=4,
+      number=5, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='versions', full_name='chromiumos.BuildReportBeta.BuildConfig.versions', index=5,
+      number=6, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='arc_use_set', full_name='chromiumos.BuildReportBeta.BuildConfig.arc_use_set', index=6,
+      number=7, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='models', full_name='chromiumos.BuildReportBeta.BuildConfig.models', index=7,
+      number=8, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
@@ -501,8 +901,9 @@
   ],
   extensions=[
   ],
-  nested_types=[_BUILDREPORTBETA_BUILDCONFIG_MODEL, _BUILDREPORTBETA_BUILDCONFIG_RELEASE, _BUILDREPORTBETA_BUILDCONFIG_BRANCH, ],
+  nested_types=[_BUILDREPORTBETA_BUILDCONFIG_MODEL, _BUILDREPORTBETA_BUILDCONFIG_RELEASE, _BUILDREPORTBETA_BUILDCONFIG_BRANCH, _BUILDREPORTBETA_BUILDCONFIG_VERSION, _BUILDREPORTBETA_BUILDCONFIG_TARGET, ],
   enum_types=[
+    _BUILDREPORTBETA_BUILDCONFIG_VERSIONKIND,
   ],
   serialized_options=None,
   is_extendable=False,
@@ -510,8 +911,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=775,
-  serialized_end=1112,
+  serialized_start=1036,
+  serialized_end=2499,
 )
 
 _BUILDREPORTBETA_BUILDARTIFACT_URI = _descriptor.Descriptor(
@@ -543,8 +944,8 @@
       name='uri', full_name='chromiumos.BuildReportBeta.BuildArtifact.URI.uri',
       index=0, containing_type=None, fields=[]),
   ],
-  serialized_start=1315,
-  serialized_end=1342,
+  serialized_start=2702,
+  serialized_end=2729,
 )
 
 _BUILDREPORTBETA_BUILDARTIFACT = _descriptor.Descriptor(
@@ -595,8 +996,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1115,
-  serialized_end=1680,
+  serialized_start=2502,
+  serialized_end=3125,
 )
 
 _BUILDREPORTBETA_STEPDETAILS_STEPINFO = _descriptor.Descriptor(
@@ -639,8 +1040,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1831,
-  serialized_end=1960,
+  serialized_start=3276,
+  serialized_end=3405,
 )
 
 _BUILDREPORTBETA_STEPDETAILS_INFOENTRY = _descriptor.Descriptor(
@@ -676,8 +1077,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1962,
-  serialized_end=2055,
+  serialized_start=3407,
+  serialized_end=3500,
 )
 
 _BUILDREPORTBETA_STEPDETAILS = _descriptor.Descriptor(
@@ -715,8 +1116,278 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1683,
-  serialized_end=2474,
+  serialized_start=3128,
+  serialized_end=3966,
+)
+
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA_FILEWITHHASHES = _descriptor.Descriptor(
+  name='FileWithHashes',
+  full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.FileWithHashes',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='filename', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.FileWithHashes.filename', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='md5', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.FileWithHashes.md5', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='sha1', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.FileWithHashes.sha1', index=2,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='sha256', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.FileWithHashes.sha256', index=3,
+      number=4, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='size', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.FileWithHashes.size', index=4,
+      number=5, type=3, cpp_type=2, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=4353,
+  serialized_end=4444,
+)
+
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA_VERSION = _descriptor.Descriptor(
+  name='Version',
+  full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.Version',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='kind', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.Version.kind', index=0,
+      number=1, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.Version.value', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=4446,
+  serialized_end=4545,
+)
+
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA = _descriptor.Descriptor(
+  name='SignedBuildMetadata',
+  full_name='chromiumos.BuildReportBeta.SignedBuildMetadata',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='status', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.status', index=0,
+      number=1, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='board', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.board', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='type', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.type', index=2,
+      number=3, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='channel', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.channel', index=3,
+      number=4, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='keyset', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.keyset', index=4,
+      number=5, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='keyset_is_mp', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.keyset_is_mp', index=5,
+      number=6, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='files', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.files', index=6,
+      number=7, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='versions', full_name='chromiumos.BuildReportBeta.SignedBuildMetadata.versions', index=7,
+      number=8, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[_BUILDREPORTBETA_SIGNEDBUILDMETADATA_FILEWITHHASHES, _BUILDREPORTBETA_SIGNEDBUILDMETADATA_VERSION, ],
+  enum_types=[
+    _BUILDREPORTBETA_SIGNEDBUILDMETADATA_VERSIONKIND,
+    _BUILDREPORTBETA_SIGNEDBUILDMETADATA_SIGNINGSTATUS,
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=3969,
+  serialized_end=5017,
+)
+
+_BUILDREPORTBETA_PAYLOAD = _descriptor.Descriptor(
+  name='Payload',
+  full_name='chromiumos.BuildReportBeta.Payload',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='payload', full_name='chromiumos.BuildReportBeta.Payload.payload', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='payload_type', full_name='chromiumos.BuildReportBeta.Payload.payload_type', index=1,
+      number=2, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='board', full_name='chromiumos.BuildReportBeta.Payload.board', index=2,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='channel', full_name='chromiumos.BuildReportBeta.Payload.channel', index=3,
+      number=4, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='appid', full_name='chromiumos.BuildReportBeta.Payload.appid', index=4,
+      number=5, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='metadata_signature', full_name='chromiumos.BuildReportBeta.Payload.metadata_signature', index=5,
+      number=6, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='metadata_size', full_name='chromiumos.BuildReportBeta.Payload.metadata_size', index=6,
+      number=7, type=3, cpp_type=2, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='source_version', full_name='chromiumos.BuildReportBeta.Payload.source_version', index=7,
+      number=8, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='target_version', full_name='chromiumos.BuildReportBeta.Payload.target_version', index=8,
+      number=9, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='size', full_name='chromiumos.BuildReportBeta.Payload.size', index=9,
+      number=10, type=3, cpp_type=2, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+    _BUILDREPORTBETA_PAYLOAD_PAYLOADTYPE,
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=5020,
+  serialized_end=5456,
 )
 
 _BUILDREPORTBETA = _descriptor.Descriptor(
@@ -734,35 +1405,70 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='type', full_name='chromiumos.BuildReportBeta.type', index=1,
+      name='count', full_name='chromiumos.BuildReportBeta.count', index=1,
+      number=8, type=3, cpp_type=2, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='parent', full_name='chromiumos.BuildReportBeta.parent', index=2,
+      number=9, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='children', full_name='chromiumos.BuildReportBeta.children', index=3,
+      number=10, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='type', full_name='chromiumos.BuildReportBeta.type', index=4,
       number=2, type=14, cpp_type=8, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='status', full_name='chromiumos.BuildReportBeta.status', index=2,
+      name='status', full_name='chromiumos.BuildReportBeta.status', index=5,
       number=3, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='config', full_name='chromiumos.BuildReportBeta.config', index=3,
+      name='config', full_name='chromiumos.BuildReportBeta.config', index=6,
       number=4, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='steps', full_name='chromiumos.BuildReportBeta.steps', index=4,
+      name='steps', full_name='chromiumos.BuildReportBeta.steps', index=7,
       number=5, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='artifacts', full_name='chromiumos.BuildReportBeta.artifacts', index=5,
+      name='signed_builds', full_name='chromiumos.BuildReportBeta.signed_builds', index=8,
+      number=6, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='payloads', full_name='chromiumos.BuildReportBeta.payloads', index=9,
+      number=11, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='artifacts', full_name='chromiumos.BuildReportBeta.artifacts', index=10,
       number=7, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
@@ -771,7 +1477,7 @@
   ],
   extensions=[
   ],
-  nested_types=[_BUILDREPORTBETA_BUILDSTATUS, _BUILDREPORTBETA_BUILDCONFIG, _BUILDREPORTBETA_BUILDARTIFACT, _BUILDREPORTBETA_STEPDETAILS, ],
+  nested_types=[_BUILDREPORTBETA_BUILDSTATUS, _BUILDREPORTBETA_BUILDCONFIG, _BUILDREPORTBETA_BUILDARTIFACT, _BUILDREPORTBETA_STEPDETAILS, _BUILDREPORTBETA_SIGNEDBUILDMETADATA, _BUILDREPORTBETA_PAYLOAD, ],
   enum_types=[
     _BUILDREPORTBETA_BUILDTYPE,
   ],
@@ -784,23 +1490,69 @@
       name='id', full_name='chromiumos.BuildReportBeta.id',
       index=0, containing_type=None, fields=[]),
   ],
-  serialized_start=201,
-  serialized_end=2592,
+  serialized_start=244,
+  serialized_end=5574,
+)
+
+
+_BUILDREPORTLIST = _descriptor.Descriptor(
+  name='BuildReportList',
+  full_name='chromiumos.BuildReportList',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='build_reports', full_name='chromiumos.BuildReportList.build_reports', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=5576,
+  serialized_end=5645,
 )
 
 _TIMEFRAME.fields_by_name['begin'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP
 _TIMEFRAME.fields_by_name['end'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP
+_BUILDID.oneofs_by_name['id'].fields.append(
+  _BUILDID.fields_by_name['buildbucket_id'])
+_BUILDID.fields_by_name['buildbucket_id'].containing_oneof = _BUILDID.oneofs_by_name['id']
 _BUILDREPORTBETA_BUILDSTATUS.fields_by_name['value'].enum_type = _BUILDREPORTBETA_BUILDSTATUS_STATUS
 _BUILDREPORTBETA_BUILDSTATUS.containing_type = _BUILDREPORTBETA
 _BUILDREPORTBETA_BUILDSTATUS_STATUS.containing_type = _BUILDREPORTBETA_BUILDSTATUS
+_BUILDREPORTBETA_BUILDCONFIG_MODEL_MODELVERSION.fields_by_name['kind'].enum_type = _BUILDREPORTBETA_BUILDCONFIG_MODEL_MODELVERSIONKIND
+_BUILDREPORTBETA_BUILDCONFIG_MODEL_MODELVERSION.containing_type = _BUILDREPORTBETA_BUILDCONFIG_MODEL
+_BUILDREPORTBETA_BUILDCONFIG_MODEL.fields_by_name['versions'].message_type = _BUILDREPORTBETA_BUILDCONFIG_MODEL_MODELVERSION
 _BUILDREPORTBETA_BUILDCONFIG_MODEL.containing_type = _BUILDREPORTBETA_BUILDCONFIG
+_BUILDREPORTBETA_BUILDCONFIG_MODEL_MODELVERSIONKIND.containing_type = _BUILDREPORTBETA_BUILDCONFIG_MODEL
 _BUILDREPORTBETA_BUILDCONFIG_RELEASE.fields_by_name['channels'].enum_type = chromiumos_dot_common__pb2._CHANNEL
 _BUILDREPORTBETA_BUILDCONFIG_RELEASE.containing_type = _BUILDREPORTBETA_BUILDCONFIG
 _BUILDREPORTBETA_BUILDCONFIG_BRANCH.containing_type = _BUILDREPORTBETA_BUILDCONFIG
+_BUILDREPORTBETA_BUILDCONFIG_VERSION.fields_by_name['kind'].enum_type = _BUILDREPORTBETA_BUILDCONFIG_VERSIONKIND
+_BUILDREPORTBETA_BUILDCONFIG_VERSION.containing_type = _BUILDREPORTBETA_BUILDCONFIG
+_BUILDREPORTBETA_BUILDCONFIG_TARGET.containing_type = _BUILDREPORTBETA_BUILDCONFIG
 _BUILDREPORTBETA_BUILDCONFIG.fields_by_name['branch'].message_type = _BUILDREPORTBETA_BUILDCONFIG_BRANCH
+_BUILDREPORTBETA_BUILDCONFIG.fields_by_name['android_container_branch'].message_type = _BUILDREPORTBETA_BUILDCONFIG_BRANCH
+_BUILDREPORTBETA_BUILDCONFIG.fields_by_name['target'].message_type = _BUILDREPORTBETA_BUILDCONFIG_TARGET
+_BUILDREPORTBETA_BUILDCONFIG.fields_by_name['android_container_target'].message_type = _BUILDREPORTBETA_BUILDCONFIG_TARGET
 _BUILDREPORTBETA_BUILDCONFIG.fields_by_name['release'].message_type = _BUILDREPORTBETA_BUILDCONFIG_RELEASE
+_BUILDREPORTBETA_BUILDCONFIG.fields_by_name['versions'].message_type = _BUILDREPORTBETA_BUILDCONFIG_VERSION
 _BUILDREPORTBETA_BUILDCONFIG.fields_by_name['models'].message_type = _BUILDREPORTBETA_BUILDCONFIG_MODEL
 _BUILDREPORTBETA_BUILDCONFIG.containing_type = _BUILDREPORTBETA
+_BUILDREPORTBETA_BUILDCONFIG_VERSIONKIND.containing_type = _BUILDREPORTBETA_BUILDCONFIG
 _BUILDREPORTBETA_BUILDARTIFACT_URI.containing_type = _BUILDREPORTBETA_BUILDARTIFACT
 _BUILDREPORTBETA_BUILDARTIFACT_URI.oneofs_by_name['uri'].fields.append(
   _BUILDREPORTBETA_BUILDARTIFACT_URI.fields_by_name['gcs'])
@@ -820,17 +1572,40 @@
 _BUILDREPORTBETA_STEPDETAILS.containing_type = _BUILDREPORTBETA
 _BUILDREPORTBETA_STEPDETAILS_STATUS.containing_type = _BUILDREPORTBETA_STEPDETAILS
 _BUILDREPORTBETA_STEPDETAILS_STEPNAME.containing_type = _BUILDREPORTBETA_STEPDETAILS
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA_FILEWITHHASHES.containing_type = _BUILDREPORTBETA_SIGNEDBUILDMETADATA
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA_VERSION.fields_by_name['kind'].enum_type = _BUILDREPORTBETA_SIGNEDBUILDMETADATA_VERSIONKIND
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA_VERSION.containing_type = _BUILDREPORTBETA_SIGNEDBUILDMETADATA
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA.fields_by_name['status'].enum_type = _BUILDREPORTBETA_SIGNEDBUILDMETADATA_SIGNINGSTATUS
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA.fields_by_name['type'].enum_type = chromiumos_dot_common__pb2._IMAGETYPE
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA.fields_by_name['channel'].enum_type = chromiumos_dot_common__pb2._CHANNEL
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA.fields_by_name['files'].message_type = _BUILDREPORTBETA_SIGNEDBUILDMETADATA_FILEWITHHASHES
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA.fields_by_name['versions'].message_type = _BUILDREPORTBETA_SIGNEDBUILDMETADATA_VERSION
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA.containing_type = _BUILDREPORTBETA
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA_VERSIONKIND.containing_type = _BUILDREPORTBETA_SIGNEDBUILDMETADATA
+_BUILDREPORTBETA_SIGNEDBUILDMETADATA_SIGNINGSTATUS.containing_type = _BUILDREPORTBETA_SIGNEDBUILDMETADATA
+_BUILDREPORTBETA_PAYLOAD.fields_by_name['payload'].message_type = _BUILDREPORTBETA_BUILDARTIFACT
+_BUILDREPORTBETA_PAYLOAD.fields_by_name['payload_type'].enum_type = _BUILDREPORTBETA_PAYLOAD_PAYLOADTYPE
+_BUILDREPORTBETA_PAYLOAD.fields_by_name['channel'].enum_type = chromiumos_dot_common__pb2._CHANNEL
+_BUILDREPORTBETA_PAYLOAD.containing_type = _BUILDREPORTBETA
+_BUILDREPORTBETA_PAYLOAD_PAYLOADTYPE.containing_type = _BUILDREPORTBETA_PAYLOAD
+_BUILDREPORTBETA.fields_by_name['parent'].message_type = _BUILDID
+_BUILDREPORTBETA.fields_by_name['children'].message_type = _BUILDID
 _BUILDREPORTBETA.fields_by_name['type'].enum_type = _BUILDREPORTBETA_BUILDTYPE
 _BUILDREPORTBETA.fields_by_name['status'].message_type = _BUILDREPORTBETA_BUILDSTATUS
 _BUILDREPORTBETA.fields_by_name['config'].message_type = _BUILDREPORTBETA_BUILDCONFIG
 _BUILDREPORTBETA.fields_by_name['steps'].message_type = _BUILDREPORTBETA_STEPDETAILS
+_BUILDREPORTBETA.fields_by_name['signed_builds'].message_type = _BUILDREPORTBETA_SIGNEDBUILDMETADATA
+_BUILDREPORTBETA.fields_by_name['payloads'].message_type = _BUILDREPORTBETA_PAYLOAD
 _BUILDREPORTBETA.fields_by_name['artifacts'].message_type = _BUILDREPORTBETA_BUILDARTIFACT
 _BUILDREPORTBETA_BUILDTYPE.containing_type = _BUILDREPORTBETA
 _BUILDREPORTBETA.oneofs_by_name['id'].fields.append(
   _BUILDREPORTBETA.fields_by_name['buildbucket_id'])
 _BUILDREPORTBETA.fields_by_name['buildbucket_id'].containing_oneof = _BUILDREPORTBETA.oneofs_by_name['id']
+_BUILDREPORTLIST.fields_by_name['build_reports'].message_type = _BUILDREPORTBETA
 DESCRIPTOR.message_types_by_name['Timeframe'] = _TIMEFRAME
+DESCRIPTOR.message_types_by_name['BuildId'] = _BUILDID
 DESCRIPTOR.message_types_by_name['BuildReportBeta'] = _BUILDREPORTBETA
+DESCRIPTOR.message_types_by_name['BuildReportList'] = _BUILDREPORTLIST
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
 Timeframe = _reflection.GeneratedProtocolMessageType('Timeframe', (_message.Message,), {
@@ -840,6 +1615,13 @@
   })
 _sym_db.RegisterMessage(Timeframe)
 
+BuildId = _reflection.GeneratedProtocolMessageType('BuildId', (_message.Message,), {
+  'DESCRIPTOR' : _BUILDID,
+  '__module__' : 'chromiumos.build_report_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.BuildId)
+  })
+_sym_db.RegisterMessage(BuildId)
+
 BuildReportBeta = _reflection.GeneratedProtocolMessageType('BuildReportBeta', (_message.Message,), {
 
   'BuildStatus' : _reflection.GeneratedProtocolMessageType('BuildStatus', (_message.Message,), {
@@ -852,6 +1634,13 @@
   'BuildConfig' : _reflection.GeneratedProtocolMessageType('BuildConfig', (_message.Message,), {
 
     'Model' : _reflection.GeneratedProtocolMessageType('Model', (_message.Message,), {
+
+      'ModelVersion' : _reflection.GeneratedProtocolMessageType('ModelVersion', (_message.Message,), {
+        'DESCRIPTOR' : _BUILDREPORTBETA_BUILDCONFIG_MODEL_MODELVERSION,
+        '__module__' : 'chromiumos.build_report_pb2'
+        # @@protoc_insertion_point(class_scope:chromiumos.BuildReportBeta.BuildConfig.Model.ModelVersion)
+        })
+      ,
       'DESCRIPTOR' : _BUILDREPORTBETA_BUILDCONFIG_MODEL,
       '__module__' : 'chromiumos.build_report_pb2'
       # @@protoc_insertion_point(class_scope:chromiumos.BuildReportBeta.BuildConfig.Model)
@@ -871,6 +1660,20 @@
       # @@protoc_insertion_point(class_scope:chromiumos.BuildReportBeta.BuildConfig.Branch)
       })
     ,
+
+    'Version' : _reflection.GeneratedProtocolMessageType('Version', (_message.Message,), {
+      'DESCRIPTOR' : _BUILDREPORTBETA_BUILDCONFIG_VERSION,
+      '__module__' : 'chromiumos.build_report_pb2'
+      # @@protoc_insertion_point(class_scope:chromiumos.BuildReportBeta.BuildConfig.Version)
+      })
+    ,
+
+    'Target' : _reflection.GeneratedProtocolMessageType('Target', (_message.Message,), {
+      'DESCRIPTOR' : _BUILDREPORTBETA_BUILDCONFIG_TARGET,
+      '__module__' : 'chromiumos.build_report_pb2'
+      # @@protoc_insertion_point(class_scope:chromiumos.BuildReportBeta.BuildConfig.Target)
+      })
+    ,
     'DESCRIPTOR' : _BUILDREPORTBETA_BUILDCONFIG,
     '__module__' : 'chromiumos.build_report_pb2'
     # @@protoc_insertion_point(class_scope:chromiumos.BuildReportBeta.BuildConfig)
@@ -911,6 +1714,34 @@
     # @@protoc_insertion_point(class_scope:chromiumos.BuildReportBeta.StepDetails)
     })
   ,
+
+  'SignedBuildMetadata' : _reflection.GeneratedProtocolMessageType('SignedBuildMetadata', (_message.Message,), {
+
+    'FileWithHashes' : _reflection.GeneratedProtocolMessageType('FileWithHashes', (_message.Message,), {
+      'DESCRIPTOR' : _BUILDREPORTBETA_SIGNEDBUILDMETADATA_FILEWITHHASHES,
+      '__module__' : 'chromiumos.build_report_pb2'
+      # @@protoc_insertion_point(class_scope:chromiumos.BuildReportBeta.SignedBuildMetadata.FileWithHashes)
+      })
+    ,
+
+    'Version' : _reflection.GeneratedProtocolMessageType('Version', (_message.Message,), {
+      'DESCRIPTOR' : _BUILDREPORTBETA_SIGNEDBUILDMETADATA_VERSION,
+      '__module__' : 'chromiumos.build_report_pb2'
+      # @@protoc_insertion_point(class_scope:chromiumos.BuildReportBeta.SignedBuildMetadata.Version)
+      })
+    ,
+    'DESCRIPTOR' : _BUILDREPORTBETA_SIGNEDBUILDMETADATA,
+    '__module__' : 'chromiumos.build_report_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.BuildReportBeta.SignedBuildMetadata)
+    })
+  ,
+
+  'Payload' : _reflection.GeneratedProtocolMessageType('Payload', (_message.Message,), {
+    'DESCRIPTOR' : _BUILDREPORTBETA_PAYLOAD,
+    '__module__' : 'chromiumos.build_report_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.BuildReportBeta.Payload)
+    })
+  ,
   'DESCRIPTOR' : _BUILDREPORTBETA,
   '__module__' : 'chromiumos.build_report_pb2'
   # @@protoc_insertion_point(class_scope:chromiumos.BuildReportBeta)
@@ -919,13 +1750,27 @@
 _sym_db.RegisterMessage(BuildReportBeta.BuildStatus)
 _sym_db.RegisterMessage(BuildReportBeta.BuildConfig)
 _sym_db.RegisterMessage(BuildReportBeta.BuildConfig.Model)
+_sym_db.RegisterMessage(BuildReportBeta.BuildConfig.Model.ModelVersion)
 _sym_db.RegisterMessage(BuildReportBeta.BuildConfig.Release)
 _sym_db.RegisterMessage(BuildReportBeta.BuildConfig.Branch)
+_sym_db.RegisterMessage(BuildReportBeta.BuildConfig.Version)
+_sym_db.RegisterMessage(BuildReportBeta.BuildConfig.Target)
 _sym_db.RegisterMessage(BuildReportBeta.BuildArtifact)
 _sym_db.RegisterMessage(BuildReportBeta.BuildArtifact.URI)
 _sym_db.RegisterMessage(BuildReportBeta.StepDetails)
 _sym_db.RegisterMessage(BuildReportBeta.StepDetails.StepInfo)
 _sym_db.RegisterMessage(BuildReportBeta.StepDetails.InfoEntry)
+_sym_db.RegisterMessage(BuildReportBeta.SignedBuildMetadata)
+_sym_db.RegisterMessage(BuildReportBeta.SignedBuildMetadata.FileWithHashes)
+_sym_db.RegisterMessage(BuildReportBeta.SignedBuildMetadata.Version)
+_sym_db.RegisterMessage(BuildReportBeta.Payload)
+
+BuildReportList = _reflection.GeneratedProtocolMessageType('BuildReportList', (_message.Message,), {
+  'DESCRIPTOR' : _BUILDREPORTLIST,
+  '__module__' : 'chromiumos.build_report_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.BuildReportList)
+  })
+_sym_db.RegisterMessage(BuildReportList)
 
 
 DESCRIPTOR._options = None
diff --git a/api/gen_sdk/chromiumos/builder_config_pb2.py b/api/gen_sdk/chromiumos/builder_config_pb2.py
index 0b90810..458939d 100644
--- a/api/gen_sdk/chromiumos/builder_config_pb2.py
+++ b/api/gen_sdk/chromiumos/builder_config_pb2.py
@@ -21,7 +21,7 @@
   package='chromiumos',
   syntax='proto3',
   serialized_options=b'\n!com.google.chrome.crosinfra.protoZ4go.chromium.org/chromiumos/infra/proto/go/chromiumos',
-  serialized_pb=b'\n\x1f\x63hromiumos/builder_config.proto\x12\nchromiumos\x1a\x17\x63hromiumos/common.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/wrappers.proto\"\xa8*\n\rBuilderConfig\x12(\n\x02id\x18\x01 \x01(\x0b\x32\x1c.chromiumos.BuilderConfig.Id\x12\x32\n\x07general\x18\x02 \x01(\x0b\x32!.chromiumos.BuilderConfig.General\x12<\n\x0corchestrator\x18\x03 \x01(\x0b\x32&.chromiumos.BuilderConfig.Orchestrator\x12\x36\n\tartifacts\x18\x04 \x01(\x0b\x32#.chromiumos.BuilderConfig.Artifacts\x12\x30\n\x06\x63hrome\x18\x05 \x01(\x0b\x32 .chromiumos.BuilderConfig.Chrome\x12.\n\x05\x62uild\x18\x06 \x01(\x0b\x32\x1f.chromiumos.BuilderConfig.Build\x12\x37\n\nunit_tests\x18\x07 \x01(\x0b\x32#.chromiumos.BuilderConfig.UnitTests\x1a\xb6\x01\n\x02Id\x12\x0c\n\x04name\x18\x01 \x01(\t\x12/\n\x04type\x18\x03 \x01(\x0e\x32!.chromiumos.BuilderConfig.Id.Type\"c\n\x04Type\x12\x14\n\x10TYPE_UNSPECIFIED\x10\x00\x12\x06\n\x02\x43Q\x10\x01\x12\x0e\n\nPOSTSUBMIT\x10\x02\x12\r\n\tTOOLCHAIN\x10\x03\x12\x11\n\rINFORMATIONAL\x10\x04\x12\x0b\n\x07RELEASE\x10\x05J\x04\x08\x02\x10\x03R\x06\x62ranch\x1a\xd6\x05\n\x07General\x12,\n\x08\x63ritical\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.BoolValue\x12\x42\n\x0b\x65nvironment\x18\x02 \x01(\x0e\x32-.chromiumos.BuilderConfig.General.Environment\x12;\n\x08run_when\x18\x03 \x01(\x0b\x32).chromiumos.BuilderConfig.General.RunWhen\x12\x31\n\rbroken_before\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x19\n\x11sdk_cache_version\x18\x05 \x01(\x05\x12\x10\n\x08unibuild\x18\x06 \x01(\x08\x12<\n\x08manifest\x18\x07 \x01(\x0e\x32*.chromiumos.BuilderConfig.General.Manifest\x12\x31\n\x11\x66irmware_location\x18\x08 \x01(\x0e\x32\x16.chromiumos.FwLocation\x1a\xc2\x01\n\x07RunWhen\x12<\n\x04mode\x18\x01 \x01(\x0e\x32..chromiumos.BuilderConfig.General.RunWhen.Mode\x12\x15\n\rfile_patterns\x18\x02 \x03(\t\"b\n\x04Mode\x12\x14\n\x10MODE_UNSPECIFIED\x10\x00\x12\x0e\n\nALWAYS_RUN\x10\x01\x12\x1a\n\x16ONLY_RUN_ON_FILE_MATCH\x10\x02\x12\x18\n\x14NO_RUN_ON_FILE_MATCH\x10\x03\"G\n\x0b\x45nvironment\x12\x1b\n\x17\x45NVIRONMENT_UNSPECIFIED\x10\x00\x12\x0e\n\nPRODUCTION\x10\x01\x12\x0b\n\x07STAGING\x10\x02\"=\n\x08Manifest\x12\x18\n\x14MANIFEST_UNSPECIFIED\x10\x00\x12\n\n\x06PUBLIC\x10\x01\x12\x0b\n\x07PRIVATE\x10\x02\x1a\xc2\x04\n\x0cOrchestrator\x12\x45\n\x0b\x63hild_specs\x18\x05 \x03(\x0b\x32\x30.chromiumos.BuilderConfig.Orchestrator.ChildSpec\x12\x31\n\x0egitiles_commit\x18\x02 \x01(\x0b\x32\x19.chromiumos.GitilesCommit\x12\x30\n\x0egerrit_changes\x18\x03 \x03(\x0b\x32\x18.chromiumos.GerritChange\x12[\n\x16\x66ollow_on_orchestrator\x18\x04 \x01(\x0b\x32;.chromiumos.BuilderConfig.Orchestrator.FollowOnOrchestrator\x1a\xe2\x01\n\tChildSpec\x12\x0c\n\x04name\x18\x01 \x01(\t\x12Z\n\x10\x63ollect_handling\x18\x02 \x01(\x0e\x32@.chromiumos.BuilderConfig.Orchestrator.ChildSpec.CollectHandling\"k\n\x0f\x43ollectHandling\x12 \n\x1c\x43OLLECT_HANDLING_UNSPECIFIED\x10\x00\x12\x0b\n\x07\x43OLLECT\x10\x01\x12\x0e\n\nNO_COLLECT\x10\x02\x12\x19\n\x15\x43OLLECT_AFTER_HW_TEST\x10\x03\x1a>\n\x14\x46ollowOnOrchestrator\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x18\n\x10\x61wait_completion\x18\x02 \x01(\x08J\x04\x08\x01\x10\x02\x1a\xd4\x0f\n\tArtifacts\x12@\n\tprebuilts\x18\x01 \x01(\x0e\x32-.chromiumos.BuilderConfig.Artifacts.Prebuilts\x12I\n\x0e\x61rtifact_types\x18\x02 \x03(\x0e\x32\x31.chromiumos.BuilderConfig.Artifacts.ArtifactTypes\x12\x1b\n\x13prebuilts_gs_bucket\x18\x03 \x01(\t\x12\x1b\n\x13\x61rtifacts_gs_bucket\x18\x04 \x01(\t\x12J\n\x11publish_artifacts\x18\x05 \x03(\x0b\x32/.chromiumos.BuilderConfig.Artifacts.PublishInfo\x12N\n\x0finput_artifacts\x18\x06 \x03(\x0b\x32\x35.chromiumos.BuilderConfig.Artifacts.InputArtifactInfo\x12>\n\x15\x61rtifact_profile_info\x18\x07 \x01(\x0b\x32\x1f.chromiumos.ArtifactProfileInfo\x12\x36\n\x0e\x61rtifacts_info\x18\x08 \x01(\x0b\x32\x1e.chromiumos.ArtifactsByService\x1a\x8c\x01\n\x0bPublishInfo\x12H\n\rpublish_types\x18\x02 \x03(\x0e\x32\x31.chromiumos.BuilderConfig.Artifacts.ArtifactTypes\x12\x1b\n\x13publish_gs_location\x18\x03 \x01(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\tJ\x04\x08\x01\x10\x02\x1a\x88\x01\n\x11InputArtifactInfo\x12N\n\x13input_artifact_type\x18\x01 \x01(\x0e\x32\x31.chromiumos.BuilderConfig.Artifacts.ArtifactTypes\x12#\n\x1binput_artifact_gs_locations\x18\x02 \x03(\t\"I\n\tPrebuilts\x12\x19\n\x15PREBUILTS_UNSPECIFIED\x10\x00\x12\n\n\x06PUBLIC\x10\x01\x12\x0b\n\x07PRIVATE\x10\x02\x12\x08\n\x04NONE\x10\x03\"\x86\t\n\rArtifactTypes\x12\x1e\n\x1a\x41RTIFACT_TYPES_UNSPECIFIED\x10\x00\x12\r\n\tIMAGE_ZIP\x10\x01\x12\x17\n\x13TEST_UPDATE_PAYLOAD\x10\x02\x12\x12\n\x0e\x41UTOTEST_FILES\x10\x03\x12\x0e\n\nTAST_FILES\x10\x04\x12\x17\n\x13PINNED_GUEST_IMAGES\x10\x05\x12\x0c\n\x08\x46IRMWARE\x10\x06\x12\x0f\n\x0b\x45\x42UILD_LOGS\x10\x07\x12\x13\n\x0f\x43HROMEOS_CONFIG\x10\x08\x12\x0e\n\nCPE_REPORT\x10\t\x12\x12\n\x0eIMAGE_ARCHIVES\x10\n\x12$\n UNVERIFIED_CHROME_LLVM_ORDERFILE\x10\x0b\x12\"\n\x1eVERIFIED_CHROME_LLVM_ORDERFILE\x10\x0c\x12\x1e\n\x1a\x43HROME_CLANG_WARNINGS_FILE\x10\r\x12\x1c\n\x18UNVERIFIED_LLVM_PGO_FILE\x10\x0e\x12)\n%UNVERIFIED_CHROME_BENCHMARK_AFDO_FILE\x10\x0f\x12\'\n#VERIFIED_CHROME_BENCHMARK_AFDO_FILE\x10\x10\x12!\n\x1dVERIFIED_KERNEL_CWP_AFDO_FILE\x10\x11\x12#\n\x1fUNVERIFIED_KERNEL_CWP_AFDO_FILE\x10\x12\x12#\n\x1fUNVERIFIED_CHROME_CWP_AFDO_FILE\x10\x13\x12!\n\x1dVERIFIED_CHROME_CWP_AFDO_FILE\x10\x14\x12\x1e\n\x1aVERIFIED_RELEASE_AFDO_FILE\x10\x15\x12)\n%UNVERIFIED_CHROME_BENCHMARK_PERF_FILE\x10\x16\x12\x17\n\x13\x43HROME_DEBUG_BINARY\x10\x17\x12\x1a\n\x16TOOLCHAIN_WARNING_LOGS\x10\x18\x12)\n%CHROME_AFDO_PROFILE_FOR_ANDROID_LINUX\x10\x19\x12\x19\n\x15\x43LANG_CRASH_DIAGNOSES\x10\x1a\x12\x13\n\x0f\x46PMCU_UNITTESTS\x10\x1b\x12\x0f\n\x0bGCE_TARBALL\x10\x1c\x12\x17\n\x13\x43OMPILER_RUSAGE_LOG\x10\x1d\x12\x14\n\x10\x46IRMWARE_TARBALL\x10\x1e\x12\x19\n\x15\x46IRMWARE_TARBALL_INFO\x10\x1f\x12\x11\n\rDEBUG_SYMBOLS\x10 \x12\x11\n\rFIRMWARE_LCOV\x10!\x12\r\n\tDLC_IMAGE\x10\"\x12\x1a\n\x16\x42REAKPAD_DEBUG_SYMBOLS\x10#\x12\x12\n\x0e\x42UILD_MANIFEST\x10$\x12\x0e\n\nUNIT_TESTS\x10%\x12\x13\n\x0fLICENSE_CREDITS\x10&\x12\x1b\n\x17\x43ODE_COVERAGE_LLVM_JSON\x10\'\x12\x19\n\x15SIMPLE_CHROME_SYSROOT\x10(\x12\x15\n\x11\x43HROME_EBUILD_ENV\x10)\x12\n\n\x06HWQUAL\x10*\x12\x11\n\rFACTORY_IMAGE\x10+\x1a\x1a\n\x06\x43hrome\x12\x10\n\x08internal\x18\x01 \x01(\x08\x1a\xae\x08\n\x05\x42uild\x12&\n\tuse_flags\x18\x01 \x03(\x0b\x32\x13.chromiumos.UseFlag\x12G\n\x0fportage_profile\x18\x02 \x01(\x0b\x32..chromiumos.BuilderConfig.Build.PortageProfile\x12\x1c\n\x14\x61pply_gerrit_changes\x18\x06 \x01(\x08\x12J\n\x11prepare_for_build\x18\x11 \x01(\x0b\x32/.chromiumos.BuilderConfig.Build.PrepareForBuild\x12=\n\nsdk_update\x18\x0c \x01(\x0b\x32).chromiumos.BuilderConfig.Build.SdkUpdate\x12K\n\x11install_toolchain\x18\r \x01(\x0b\x32\x30.chromiumos.BuilderConfig.Build.InstallToolchain\x12I\n\x10install_packages\x18\x10 \x01(\x0b\x32/.chromiumos.BuilderConfig.Build.InstallPackages\x12\x41\n\x0c\x62uild_images\x18\x0f \x01(\x0b\x32+.chromiumos.BuilderConfig.Build.BuildImages\x1a!\n\x0ePortageProfile\x12\x0f\n\x07profile\x18\x01 \x01(\t\x1aU\n\x0fPrepareForBuild\x12\x42\n\x0f\x61\x64\x64itional_args\x18\x01 \x01(\x0b\x32).chromiumos.PrepareForBuildAdditionalArgs\x1a#\n\tSdkUpdate\x12\x16\n\x0e\x63ompile_source\x18\x01 \x01(\x08\x1a*\n\x10InstallToolchain\x12\x16\n\x0e\x63ompile_source\x18\x01 \x01(\x08\x1a\xdd\x01\n\x0fInstallPackages\x12\x16\n\x0e\x63ompile_source\x18\x01 \x01(\x08\x12\x33\n\x08run_spec\x18\x02 \x01(\x0e\x32!.chromiumos.BuilderConfig.RunSpec\x12)\n\x08packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\x14\n\x0c\x64isable_goma\x18\x04 \x01(\x08\x12<\n\x0c\x64\x65pendencies\x18\x05 \x01(\x0e\x32&.chromiumos.BuilderConfig.Dependencies\x1as\n\x0b\x42uildImages\x12*\n\x0bimage_types\x18\x01 \x03(\x0e\x32\x15.chromiumos.ImageType\x12#\n\x1b\x64isable_rootfs_verification\x18\x02 \x01(\x08\x12\x13\n\x0b\x64isk_layout\x18\x03 \x01(\tJ\x04\x08\x03\x10\x06J\x04\x08\x07\x10\x0cJ\x04\x08\x0e\x10\x0f\x1a\x82\x02\n\tUnitTests\x12;\n\x10\x65\x62uilds_run_spec\x18\x05 \x01(\x0e\x32!.chromiumos.BuilderConfig.RunSpec\x12\x15\n\rempty_sysroot\x18\x06 \x01(\x08\x12)\n\x08packages\x18\x07 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12<\n\x0c\x64\x65pendencies\x18\x08 \x01(\x0e\x32&.chromiumos.BuilderConfig.Dependencies\x12\x32\n\x11package_blocklist\x18\t \x03(\x0b\x32\x17.chromiumos.PackageInfoJ\x04\x08\x04\x10\x05\"F\n\x07RunSpec\x12\x18\n\x14RUN_SPEC_UNSPECIFIED\x10\x00\x12\n\n\x06NO_RUN\x10\x01\x12\x07\n\x03RUN\x10\x02\x12\x0c\n\x08RUN_EXIT\x10\x03\"`\n\x0c\x44\x65pendencies\x12\x1c\n\x18\x44\x45PENDENCIES_UNSPECIFIED\x10\x00\x12\x14\n\x10\x41LL_DEPENDENCIES\x10\x01\x12\x1c\n\x18\x43L_AFFECTED_DEPENDENCIES\x10\x02\"D\n\x0e\x42uilderConfigs\x12\x32\n\x0f\x62uilder_configs\x18\x01 \x03(\x0b\x32\x19.chromiumos.BuilderConfigBY\n!com.google.chrome.crosinfra.protoZ4go.chromium.org/chromiumos/infra/proto/go/chromiumosb\x06proto3'
+  serialized_pb=b'\n\x1f\x63hromiumos/builder_config.proto\x12\nchromiumos\x1a\x17\x63hromiumos/common.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/wrappers.proto\"\xe0*\n\rBuilderConfig\x12(\n\x02id\x18\x01 \x01(\x0b\x32\x1c.chromiumos.BuilderConfig.Id\x12\x32\n\x07general\x18\x02 \x01(\x0b\x32!.chromiumos.BuilderConfig.General\x12<\n\x0corchestrator\x18\x03 \x01(\x0b\x32&.chromiumos.BuilderConfig.Orchestrator\x12\x36\n\tartifacts\x18\x04 \x01(\x0b\x32#.chromiumos.BuilderConfig.Artifacts\x12\x30\n\x06\x63hrome\x18\x05 \x01(\x0b\x32 .chromiumos.BuilderConfig.Chrome\x12.\n\x05\x62uild\x18\x06 \x01(\x0b\x32\x1f.chromiumos.BuilderConfig.Build\x12\x37\n\nunit_tests\x18\x07 \x01(\x0b\x32#.chromiumos.BuilderConfig.UnitTests\x1a\xb6\x01\n\x02Id\x12\x0c\n\x04name\x18\x01 \x01(\t\x12/\n\x04type\x18\x03 \x01(\x0e\x32!.chromiumos.BuilderConfig.Id.Type\"c\n\x04Type\x12\x14\n\x10TYPE_UNSPECIFIED\x10\x00\x12\x06\n\x02\x43Q\x10\x01\x12\x0e\n\nPOSTSUBMIT\x10\x02\x12\r\n\tTOOLCHAIN\x10\x03\x12\x11\n\rINFORMATIONAL\x10\x04\x12\x0b\n\x07RELEASE\x10\x05J\x04\x08\x02\x10\x03R\x06\x62ranch\x1a\xd6\x05\n\x07General\x12,\n\x08\x63ritical\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.BoolValue\x12\x42\n\x0b\x65nvironment\x18\x02 \x01(\x0e\x32-.chromiumos.BuilderConfig.General.Environment\x12;\n\x08run_when\x18\x03 \x01(\x0b\x32).chromiumos.BuilderConfig.General.RunWhen\x12\x31\n\rbroken_before\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x19\n\x11sdk_cache_version\x18\x05 \x01(\x05\x12\x10\n\x08unibuild\x18\x06 \x01(\x08\x12<\n\x08manifest\x18\x07 \x01(\x0e\x32*.chromiumos.BuilderConfig.General.Manifest\x12\x31\n\x11\x66irmware_location\x18\x08 \x01(\x0e\x32\x16.chromiumos.FwLocation\x1a\xc2\x01\n\x07RunWhen\x12<\n\x04mode\x18\x01 \x01(\x0e\x32..chromiumos.BuilderConfig.General.RunWhen.Mode\x12\x15\n\rfile_patterns\x18\x02 \x03(\t\"b\n\x04Mode\x12\x14\n\x10MODE_UNSPECIFIED\x10\x00\x12\x0e\n\nALWAYS_RUN\x10\x01\x12\x1a\n\x16ONLY_RUN_ON_FILE_MATCH\x10\x02\x12\x18\n\x14NO_RUN_ON_FILE_MATCH\x10\x03\"G\n\x0b\x45nvironment\x12\x1b\n\x17\x45NVIRONMENT_UNSPECIFIED\x10\x00\x12\x0e\n\nPRODUCTION\x10\x01\x12\x0b\n\x07STAGING\x10\x02\"=\n\x08Manifest\x12\x18\n\x14MANIFEST_UNSPECIFIED\x10\x00\x12\n\n\x06PUBLIC\x10\x01\x12\x0b\n\x07PRIVATE\x10\x02\x1a\xe2\x04\n\x0cOrchestrator\x12\x45\n\x0b\x63hild_specs\x18\x05 \x03(\x0b\x32\x30.chromiumos.BuilderConfig.Orchestrator.ChildSpec\x12\x31\n\x0egitiles_commit\x18\x02 \x01(\x0b\x32\x19.chromiumos.GitilesCommit\x12\x30\n\x0egerrit_changes\x18\x03 \x03(\x0b\x32\x18.chromiumos.GerritChange\x12[\n\x16\x66ollow_on_orchestrator\x18\x04 \x01(\x0b\x32;.chromiumos.BuilderConfig.Orchestrator.FollowOnOrchestrator\x12\x1e\n\x16require_stable_devices\x18\x06 \x01(\x08\x1a\xe2\x01\n\tChildSpec\x12\x0c\n\x04name\x18\x01 \x01(\t\x12Z\n\x10\x63ollect_handling\x18\x02 \x01(\x0e\x32@.chromiumos.BuilderConfig.Orchestrator.ChildSpec.CollectHandling\"k\n\x0f\x43ollectHandling\x12 \n\x1c\x43OLLECT_HANDLING_UNSPECIFIED\x10\x00\x12\x0b\n\x07\x43OLLECT\x10\x01\x12\x0e\n\nNO_COLLECT\x10\x02\x12\x19\n\x15\x43OLLECT_AFTER_HW_TEST\x10\x03\x1a>\n\x14\x46ollowOnOrchestrator\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x18\n\x10\x61wait_completion\x18\x02 \x01(\x08J\x04\x08\x01\x10\x02\x1a\xd4\x0f\n\tArtifacts\x12@\n\tprebuilts\x18\x01 \x01(\x0e\x32-.chromiumos.BuilderConfig.Artifacts.Prebuilts\x12I\n\x0e\x61rtifact_types\x18\x02 \x03(\x0e\x32\x31.chromiumos.BuilderConfig.Artifacts.ArtifactTypes\x12\x1b\n\x13prebuilts_gs_bucket\x18\x03 \x01(\t\x12\x1b\n\x13\x61rtifacts_gs_bucket\x18\x04 \x01(\t\x12J\n\x11publish_artifacts\x18\x05 \x03(\x0b\x32/.chromiumos.BuilderConfig.Artifacts.PublishInfo\x12N\n\x0finput_artifacts\x18\x06 \x03(\x0b\x32\x35.chromiumos.BuilderConfig.Artifacts.InputArtifactInfo\x12>\n\x15\x61rtifact_profile_info\x18\x07 \x01(\x0b\x32\x1f.chromiumos.ArtifactProfileInfo\x12\x36\n\x0e\x61rtifacts_info\x18\x08 \x01(\x0b\x32\x1e.chromiumos.ArtifactsByService\x1a\x8c\x01\n\x0bPublishInfo\x12H\n\rpublish_types\x18\x02 \x03(\x0e\x32\x31.chromiumos.BuilderConfig.Artifacts.ArtifactTypes\x12\x1b\n\x13publish_gs_location\x18\x03 \x01(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\tJ\x04\x08\x01\x10\x02\x1a\x88\x01\n\x11InputArtifactInfo\x12N\n\x13input_artifact_type\x18\x01 \x01(\x0e\x32\x31.chromiumos.BuilderConfig.Artifacts.ArtifactTypes\x12#\n\x1binput_artifact_gs_locations\x18\x02 \x03(\t\"I\n\tPrebuilts\x12\x19\n\x15PREBUILTS_UNSPECIFIED\x10\x00\x12\n\n\x06PUBLIC\x10\x01\x12\x0b\n\x07PRIVATE\x10\x02\x12\x08\n\x04NONE\x10\x03\"\x86\t\n\rArtifactTypes\x12\x1e\n\x1a\x41RTIFACT_TYPES_UNSPECIFIED\x10\x00\x12\r\n\tIMAGE_ZIP\x10\x01\x12\x17\n\x13TEST_UPDATE_PAYLOAD\x10\x02\x12\x12\n\x0e\x41UTOTEST_FILES\x10\x03\x12\x0e\n\nTAST_FILES\x10\x04\x12\x17\n\x13PINNED_GUEST_IMAGES\x10\x05\x12\x0c\n\x08\x46IRMWARE\x10\x06\x12\x0f\n\x0b\x45\x42UILD_LOGS\x10\x07\x12\x13\n\x0f\x43HROMEOS_CONFIG\x10\x08\x12\x0e\n\nCPE_REPORT\x10\t\x12\x12\n\x0eIMAGE_ARCHIVES\x10\n\x12$\n UNVERIFIED_CHROME_LLVM_ORDERFILE\x10\x0b\x12\"\n\x1eVERIFIED_CHROME_LLVM_ORDERFILE\x10\x0c\x12\x1e\n\x1a\x43HROME_CLANG_WARNINGS_FILE\x10\r\x12\x1c\n\x18UNVERIFIED_LLVM_PGO_FILE\x10\x0e\x12)\n%UNVERIFIED_CHROME_BENCHMARK_AFDO_FILE\x10\x0f\x12\'\n#VERIFIED_CHROME_BENCHMARK_AFDO_FILE\x10\x10\x12!\n\x1dVERIFIED_KERNEL_CWP_AFDO_FILE\x10\x11\x12#\n\x1fUNVERIFIED_KERNEL_CWP_AFDO_FILE\x10\x12\x12#\n\x1fUNVERIFIED_CHROME_CWP_AFDO_FILE\x10\x13\x12!\n\x1dVERIFIED_CHROME_CWP_AFDO_FILE\x10\x14\x12\x1e\n\x1aVERIFIED_RELEASE_AFDO_FILE\x10\x15\x12)\n%UNVERIFIED_CHROME_BENCHMARK_PERF_FILE\x10\x16\x12\x17\n\x13\x43HROME_DEBUG_BINARY\x10\x17\x12\x1a\n\x16TOOLCHAIN_WARNING_LOGS\x10\x18\x12)\n%CHROME_AFDO_PROFILE_FOR_ANDROID_LINUX\x10\x19\x12\x19\n\x15\x43LANG_CRASH_DIAGNOSES\x10\x1a\x12\x13\n\x0f\x46PMCU_UNITTESTS\x10\x1b\x12\x0f\n\x0bGCE_TARBALL\x10\x1c\x12\x17\n\x13\x43OMPILER_RUSAGE_LOG\x10\x1d\x12\x14\n\x10\x46IRMWARE_TARBALL\x10\x1e\x12\x19\n\x15\x46IRMWARE_TARBALL_INFO\x10\x1f\x12\x11\n\rDEBUG_SYMBOLS\x10 \x12\x11\n\rFIRMWARE_LCOV\x10!\x12\r\n\tDLC_IMAGE\x10\"\x12\x1a\n\x16\x42REAKPAD_DEBUG_SYMBOLS\x10#\x12\x12\n\x0e\x42UILD_MANIFEST\x10$\x12\x0e\n\nUNIT_TESTS\x10%\x12\x13\n\x0fLICENSE_CREDITS\x10&\x12\x1b\n\x17\x43ODE_COVERAGE_LLVM_JSON\x10\'\x12\x19\n\x15SIMPLE_CHROME_SYSROOT\x10(\x12\x15\n\x11\x43HROME_EBUILD_ENV\x10)\x12\n\n\x06HWQUAL\x10*\x12\x11\n\rFACTORY_IMAGE\x10+\x1a\x1a\n\x06\x43hrome\x12\x10\n\x08internal\x18\x01 \x01(\x08\x1a\xc6\x08\n\x05\x42uild\x12&\n\tuse_flags\x18\x01 \x03(\x0b\x32\x13.chromiumos.UseFlag\x12G\n\x0fportage_profile\x18\x02 \x01(\x0b\x32..chromiumos.BuilderConfig.Build.PortageProfile\x12\x1c\n\x14\x61pply_gerrit_changes\x18\x06 \x01(\x08\x12J\n\x11prepare_for_build\x18\x11 \x01(\x0b\x32/.chromiumos.BuilderConfig.Build.PrepareForBuild\x12=\n\nsdk_update\x18\x0c \x01(\x0b\x32).chromiumos.BuilderConfig.Build.SdkUpdate\x12K\n\x11install_toolchain\x18\r \x01(\x0b\x32\x30.chromiumos.BuilderConfig.Build.InstallToolchain\x12I\n\x10install_packages\x18\x10 \x01(\x0b\x32/.chromiumos.BuilderConfig.Build.InstallPackages\x12\x41\n\x0c\x62uild_images\x18\x0f \x01(\x0b\x32+.chromiumos.BuilderConfig.Build.BuildImages\x1a!\n\x0ePortageProfile\x12\x0f\n\x07profile\x18\x01 \x01(\t\x1aU\n\x0fPrepareForBuild\x12\x42\n\x0f\x61\x64\x64itional_args\x18\x01 \x01(\x0b\x32).chromiumos.PrepareForBuildAdditionalArgs\x1a#\n\tSdkUpdate\x12\x16\n\x0e\x63ompile_source\x18\x01 \x01(\x08\x1a*\n\x10InstallToolchain\x12\x16\n\x0e\x63ompile_source\x18\x01 \x01(\x08\x1a\xf5\x01\n\x0fInstallPackages\x12\x16\n\x0e\x63ompile_source\x18\x01 \x01(\x08\x12\x33\n\x08run_spec\x18\x02 \x01(\x0e\x32!.chromiumos.BuilderConfig.RunSpec\x12)\n\x08packages\x18\x03 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12\x14\n\x0c\x64isable_goma\x18\x04 \x01(\x08\x12\x16\n\x0euse_remoteexec\x18\x06 \x01(\x08\x12<\n\x0c\x64\x65pendencies\x18\x05 \x01(\x0e\x32&.chromiumos.BuilderConfig.Dependencies\x1as\n\x0b\x42uildImages\x12*\n\x0bimage_types\x18\x01 \x03(\x0e\x32\x15.chromiumos.ImageType\x12#\n\x1b\x64isable_rootfs_verification\x18\x02 \x01(\x08\x12\x13\n\x0b\x64isk_layout\x18\x03 \x01(\tJ\x04\x08\x03\x10\x06J\x04\x08\x07\x10\x0cJ\x04\x08\x0e\x10\x0f\x1a\x82\x02\n\tUnitTests\x12;\n\x10\x65\x62uilds_run_spec\x18\x05 \x01(\x0e\x32!.chromiumos.BuilderConfig.RunSpec\x12\x15\n\rempty_sysroot\x18\x06 \x01(\x08\x12)\n\x08packages\x18\x07 \x03(\x0b\x32\x17.chromiumos.PackageInfo\x12<\n\x0c\x64\x65pendencies\x18\x08 \x01(\x0e\x32&.chromiumos.BuilderConfig.Dependencies\x12\x32\n\x11package_blocklist\x18\t \x03(\x0b\x32\x17.chromiumos.PackageInfoJ\x04\x08\x04\x10\x05\"F\n\x07RunSpec\x12\x18\n\x14RUN_SPEC_UNSPECIFIED\x10\x00\x12\n\n\x06NO_RUN\x10\x01\x12\x07\n\x03RUN\x10\x02\x12\x0c\n\x08RUN_EXIT\x10\x03\"`\n\x0c\x44\x65pendencies\x12\x1c\n\x18\x44\x45PENDENCIES_UNSPECIFIED\x10\x00\x12\x14\n\x10\x41LL_DEPENDENCIES\x10\x01\x12\x1c\n\x18\x43L_AFFECTED_DEPENDENCIES\x10\x02\"D\n\x0e\x42uilderConfigs\x12\x32\n\x0f\x62uilder_configs\x18\x01 \x03(\x0b\x32\x19.chromiumos.BuilderConfigBY\n!com.google.chrome.crosinfra.protoZ4go.chromium.org/chromiumos/infra/proto/go/chromiumosb\x06proto3'
   ,
   dependencies=[chromiumos_dot_common__pb2.DESCRIPTOR,google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,google_dot_protobuf_dot_wrappers__pb2.DESCRIPTOR,])
 
@@ -172,8 +172,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1838,
-  serialized_end=1945,
+  serialized_start=1870,
+  serialized_end=1977,
 )
 _sym_db.RegisterEnumDescriptor(_BUILDERCONFIG_ORCHESTRATOR_CHILDSPEC_COLLECTHANDLING)
 
@@ -202,8 +202,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2788,
-  serialized_end=2861,
+  serialized_start=2820,
+  serialized_end=2893,
 )
 _sym_db.RegisterEnumDescriptor(_BUILDERCONFIG_ARTIFACTS_PREBUILTS)
 
@@ -392,8 +392,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2864,
-  serialized_end=4022,
+  serialized_start=2896,
+  serialized_end=4054,
 )
 _sym_db.RegisterEnumDescriptor(_BUILDERCONFIG_ARTIFACTS_ARTIFACTTYPES)
 
@@ -422,8 +422,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=5386,
-  serialized_end=5456,
+  serialized_start=5442,
+  serialized_end=5512,
 )
 _sym_db.RegisterEnumDescriptor(_BUILDERCONFIG_RUNSPEC)
 
@@ -448,8 +448,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=5458,
-  serialized_end=5554,
+  serialized_start=5514,
+  serialized_end=5610,
 )
 _sym_db.RegisterEnumDescriptor(_BUILDERCONFIG_DEPENDENCIES)
 
@@ -645,8 +645,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1719,
-  serialized_end=1945,
+  serialized_start=1751,
+  serialized_end=1977,
 )
 
 _BUILDERCONFIG_ORCHESTRATOR_FOLLOWONORCHESTRATOR = _descriptor.Descriptor(
@@ -682,8 +682,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1947,
-  serialized_end=2009,
+  serialized_start=1979,
+  serialized_end=2041,
 )
 
 _BUILDERCONFIG_ORCHESTRATOR = _descriptor.Descriptor(
@@ -721,6 +721,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='require_stable_devices', full_name='chromiumos.BuilderConfig.Orchestrator.require_stable_devices', index=4,
+      number=6, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -734,7 +741,7 @@
   oneofs=[
   ],
   serialized_start=1437,
-  serialized_end=2015,
+  serialized_end=2047,
 )
 
 _BUILDERCONFIG_ARTIFACTS_PUBLISHINFO = _descriptor.Descriptor(
@@ -777,8 +784,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2507,
-  serialized_end=2647,
+  serialized_start=2539,
+  serialized_end=2679,
 )
 
 _BUILDERCONFIG_ARTIFACTS_INPUTARTIFACTINFO = _descriptor.Descriptor(
@@ -814,8 +821,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2650,
-  serialized_end=2786,
+  serialized_start=2682,
+  serialized_end=2818,
 )
 
 _BUILDERCONFIG_ARTIFACTS = _descriptor.Descriptor(
@@ -895,8 +902,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2018,
-  serialized_end=4022,
+  serialized_start=2050,
+  serialized_end=4054,
 )
 
 _BUILDERCONFIG_CHROME = _descriptor.Descriptor(
@@ -925,8 +932,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4024,
-  serialized_end=4050,
+  serialized_start=4056,
+  serialized_end=4082,
 )
 
 _BUILDERCONFIG_BUILD_PORTAGEPROFILE = _descriptor.Descriptor(
@@ -955,8 +962,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4563,
-  serialized_end=4596,
+  serialized_start=4595,
+  serialized_end=4628,
 )
 
 _BUILDERCONFIG_BUILD_PREPAREFORBUILD = _descriptor.Descriptor(
@@ -985,8 +992,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4598,
-  serialized_end=4683,
+  serialized_start=4630,
+  serialized_end=4715,
 )
 
 _BUILDERCONFIG_BUILD_SDKUPDATE = _descriptor.Descriptor(
@@ -1015,8 +1022,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4685,
-  serialized_end=4720,
+  serialized_start=4717,
+  serialized_end=4752,
 )
 
 _BUILDERCONFIG_BUILD_INSTALLTOOLCHAIN = _descriptor.Descriptor(
@@ -1045,8 +1052,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4722,
-  serialized_end=4764,
+  serialized_start=4754,
+  serialized_end=4796,
 )
 
 _BUILDERCONFIG_BUILD_INSTALLPACKAGES = _descriptor.Descriptor(
@@ -1085,7 +1092,14 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='dependencies', full_name='chromiumos.BuilderConfig.Build.InstallPackages.dependencies', index=4,
+      name='use_remoteexec', full_name='chromiumos.BuilderConfig.Build.InstallPackages.use_remoteexec', index=4,
+      number=6, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='dependencies', full_name='chromiumos.BuilderConfig.Build.InstallPackages.dependencies', index=5,
       number=5, type=14, cpp_type=8, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
@@ -1103,8 +1117,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4767,
-  serialized_end=4988,
+  serialized_start=4799,
+  serialized_end=5044,
 )
 
 _BUILDERCONFIG_BUILD_BUILDIMAGES = _descriptor.Descriptor(
@@ -1147,8 +1161,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4990,
-  serialized_end=5105,
+  serialized_start=5046,
+  serialized_end=5161,
 )
 
 _BUILDERCONFIG_BUILD = _descriptor.Descriptor(
@@ -1226,8 +1240,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4053,
-  serialized_end=5123,
+  serialized_start=4085,
+  serialized_end=5179,
 )
 
 _BUILDERCONFIG_UNITTESTS = _descriptor.Descriptor(
@@ -1284,8 +1298,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5126,
-  serialized_end=5384,
+  serialized_start=5182,
+  serialized_end=5440,
 )
 
 _BUILDERCONFIG = _descriptor.Descriptor(
@@ -1359,7 +1373,7 @@
   oneofs=[
   ],
   serialized_start=138,
-  serialized_end=5554,
+  serialized_end=5610,
 )
 
 
@@ -1389,8 +1403,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5556,
-  serialized_end=5624,
+  serialized_start=5612,
+  serialized_end=5680,
 )
 
 _BUILDERCONFIG_ID.fields_by_name['type'].enum_type = _BUILDERCONFIG_ID_TYPE
diff --git a/api/gen_sdk/chromiumos/common_pb2.py b/api/gen_sdk/chromiumos/common_pb2.py
index 95e9339..b02d5a4 100644
--- a/api/gen_sdk/chromiumos/common_pb2.py
+++ b/api/gen_sdk/chromiumos/common_pb2.py
@@ -19,7 +19,7 @@
   package='chromiumos',
   syntax='proto3',
   serialized_options=b'\n!com.google.chrome.crosinfra.protoZ4go.chromium.org/chromiumos/infra/proto/go/chromiumos',
-  serialized_pb=b'\n\x17\x63hromiumos/common.proto\x12\nchromiumos\"\x1b\n\x0b\x42uildTarget\x12\x0c\n\x04name\x18\x01 \x01(\t\"\'\n\x07GcsPath\x12\x0e\n\x06\x62ucket\x18\x01 \x01(\t\x12\x0c\n\x04path\x18\x02 \x01(\t\"\xd0\x01\n\x06\x43hroot\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x11\n\tcache_dir\x18\x02 \x01(\t\x12)\n\x03\x65nv\x18\x03 \x01(\x0b\x32\x1c.chromiumos.Chroot.ChrootEnv\x12\x12\n\nchrome_dir\x18\x04 \x01(\t\x1aZ\n\tChrootEnv\x12&\n\tuse_flags\x18\x01 \x03(\x0b\x32\x13.chromiumos.UseFlag\x12%\n\x08\x66\x65\x61tures\x18\x02 \x03(\x0b\x32\x13.chromiumos.FeatureJ\x04\x08\x05\x10\x06R\x04goma\"\x1a\n\x07\x46\x65\x61ture\x12\x0f\n\x07\x66\x65\x61ture\x18\x01 \x01(\t\"\xcf\x02\n\nGomaConfig\x12\x10\n\x08goma_dir\x18\x01 \x01(\t\x12\x18\n\x10goma_client_json\x18\x02 \x01(\t\x12\x19\n\x11\x63hromeos_goma_dir\x18\x03 \x01(\t\x12:\n\rgoma_approach\x18\x04 \x01(\x0e\x32#.chromiumos.GomaConfig.GomaApproach\x12&\n\x07log_dir\x18\x05 \x01(\x0b\x32\x15.chromiumos.SyncedDir\x12\x12\n\nstats_file\x18\x06 \x01(\t\x12\x15\n\rcounterz_file\x18\x07 \x01(\t\"k\n\x0cGomaApproach\x12\x1d\n\x19GOMA_APPROACH_UNSPECIFIED\x10\x00\x12\x0b\n\x07\x44\x45\x46\x41ULT\x10\x01\x12\x0c\n\x08RBE_PROD\x10\x02\x12\x0f\n\x0bRBE_STAGING\x10\x03\x12\x10\n\x0cRBE_CHROMEOS\x10\x04\"M\n\rGomaArtifacts\x12\x12\n\nstats_file\x18\x01 \x01(\t\x12\x15\n\rcounterz_file\x18\x02 \x01(\t\x12\x11\n\tlog_files\x18\x03 \x03(\t\"F\n\x0bPackageInfo\x12\x14\n\x0cpackage_name\x18\x01 \x01(\t\x12\x10\n\x08\x63\x61tegory\x18\x02 \x01(\t\x12\x0f\n\x07version\x18\x03 \x01(\t\"\x17\n\x07Profile\x12\x0c\n\x04name\x18\x01 \x01(\t\"\xa8\x01\n\x10PackageIndexInfo\x12\x14\n\x0csnapshot_sha\x18\x01 \x01(\t\x12\x17\n\x0fsnapshot_number\x18\x02 \x01(\x05\x12-\n\x0c\x62uild_target\x18\x03 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x10\n\x08location\x18\x04 \x01(\t\x12$\n\x07profile\x18\x05 \x01(\x0b\x32\x13.chromiumos.Profile\"w\n\x04Path\x12\x0c\n\x04path\x18\x01 \x01(\t\x12+\n\x08location\x18\x02 \x01(\x0e\x32\x19.chromiumos.Path.Location\"4\n\x08Location\x12\x0f\n\x0bNO_LOCATION\x10\x00\x12\n\n\x06INSIDE\x10\x01\x12\x0b\n\x07OUTSIDE\x10\x02\",\n\nResultPath\x12\x1e\n\x04path\x18\x01 \x01(\x0b\x32\x10.chromiumos.Path\"\x18\n\tSyncedDir\x12\x0b\n\x03\x64ir\x18\x01 \x01(\t\"O\n\x0cGerritChange\x12\x0c\n\x04host\x18\x01 \x01(\t\x12\x0f\n\x07project\x18\x02 \x01(\t\x12\x0e\n\x06\x63hange\x18\x03 \x01(\x03\x12\x10\n\x08patchset\x18\x04 \x01(\x03\"Y\n\rGitilesCommit\x12\x0c\n\x04host\x18\x01 \x01(\t\x12\x0f\n\x07project\x18\x02 \x01(\t\x12\n\n\x02id\x18\x03 \x01(\t\x12\x0b\n\x03ref\x18\x04 \x01(\t\x12\x10\n\x08position\x18\x05 \x01(\r\"\x17\n\x07UseFlag\x12\x0c\n\x04\x66lag\x18\x01 \x01(\t\"\xb8\x02\n\x0eReleaseBuilder\x12\x39\n\tmilestone\x18\x01 \x01(\x0b\x32$.chromiumos.ReleaseBuilder.MilestoneH\x00\x12\x16\n\x0e\x62uild_schedule\x18\x02 \x01(\t\x12\x38\n\x0f\x65xpiration_date\x18\x03 \x01(\x0b\x32\x1f.chromiumos.ReleaseBuilder.Date\x1a\x15\n\x04\x44\x61te\x12\r\n\x05value\x18\x01 \x01(\t\x1am\n\tMilestone\x12\x0e\n\x06number\x18\x01 \x01(\x05\x12;\n\x12target_branch_date\x18\x02 \x01(\x0b\x32\x1f.chromiumos.ReleaseBuilder.Date\x12\x13\n\x0b\x62ranch_name\x18\x03 \x01(\tB\x13\n\x11milestone_message\"?\n\x0fReleaseBuilders\x12,\n\x08\x62uilders\x18\x01 \x03(\x0b\x32\x1a.chromiumos.ReleaseBuilder\"\xf4\x01\n\x0fReleaseChannels\x12J\n\x10release_channels\x18\x01 \x03(\x0b\x32\x30.chromiumos.ReleaseChannels.ReleaseChannelsEntry\x1a\x34\n\x0b\x43hannelList\x12%\n\x08\x63hannels\x18\x01 \x03(\x0e\x32\x13.chromiumos.Channel\x1a_\n\x14ReleaseChannelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\x36\n\x05value\x18\x02 \x01(\x0b\x32\'.chromiumos.ReleaseChannels.ChannelList:\x02\x38\x01\"&\n\nProtoBytes\x12\x18\n\x10serialized_proto\x18\x01 \x01(\x0c\"q\n\x1dPrepareForBuildAdditionalArgs\x12\x1c\n\x12\x63hrome_cwp_profile\x18\x01 \x01(\tH\x00\x12\x18\n\x0ekernel_version\x18\x02 \x01(\tH\x00\x42\x18\n\x16prepare_for_build_args\"A\n\x0b\x41\x66\x64oRelease\x12\x1a\n\x12\x63hrome_cwp_profile\x18\x01 \x01(\t\x12\x16\n\x0eimage_build_id\x18\x02 \x01(\x03\"\x97\x01\n\x13\x41rtifactProfileInfo\x12\x1c\n\x12\x63hrome_cwp_profile\x18\x01 \x01(\tH\x00\x12\x18\n\x0ekernel_version\x18\x02 \x01(\tH\x00\x12/\n\x0c\x61\x66\x64o_release\x18\x03 \x01(\x0b\x32\x17.chromiumos.AfdoReleaseH\x00\x42\x17\n\x15\x61rtifact_profile_info\"\xbe+\n\x12\x41rtifactsByService\x12\x35\n\x06legacy\x18\x01 \x01(\x0b\x32%.chromiumos.ArtifactsByService.Legacy\x12;\n\ttoolchain\x18\x02 \x01(\x0b\x32(.chromiumos.ArtifactsByService.Toolchain\x12\x33\n\x05image\x18\x03 \x01(\x0b\x32$.chromiumos.ArtifactsByService.Image\x12\x37\n\x07package\x18\x04 \x01(\x0b\x32&.chromiumos.ArtifactsByService.Package\x12\x37\n\x07sysroot\x18\x05 \x01(\x0b\x32&.chromiumos.ArtifactsByService.Sysroot\x12\x31\n\x04test\x18\x06 \x01(\x0b\x32#.chromiumos.ArtifactsByService.Test\x12\x35\n\x0cprofile_info\x18\x07 \x01(\x0b\x32\x1f.chromiumos.ArtifactProfileInfo\x12\x39\n\x08\x66irmware\x18\x08 \x01(\x0b\x32\'.chromiumos.ArtifactsByService.Firmware\x12\x33\n\x05infra\x18\t \x01(\x0b\x32$.chromiumos.ArtifactsByService.Infra\x1a\xb0\x01\n\x16\x43odeCoverageUploadInfo\x12]\n\rcoverage_type\x18\x01 \x01(\x0e\x32\x46.chromiumos.ArtifactsByService.CodeCoverageUploadInfo.CodeCoverageType\"7\n\x10\x43odeCoverageType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x08\n\x04LLVM\x10\x01\x12\x08\n\x04LCOV\x10\x02\x1a\xb2\x05\n\x06Legacy\x12K\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x32.chromiumos.ArtifactsByService.Legacy.ArtifactInfo\x12L\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x32.chromiumos.ArtifactsByService.Legacy.ArtifactInfo\x1a\xe2\x01\n\x0c\x41rtifactInfo\x12J\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x32.chromiumos.ArtifactsByService.Legacy.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\t\x12J\n\x11publish_condition\x18\x05 \x01(\x0e\x32/.chromiumos.ArtifactsByService.PublishConditionJ\x04\x08\x03\x10\x04R\x0cprofile_info\"\xa7\x02\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\r\n\tIMAGE_ZIP\x10\x01\x12\x17\n\x13TEST_UPDATE_PAYLOAD\x10\x02\x12\x12\n\x0e\x41UTOTEST_FILES\x10\x03\x12\x0e\n\nTAST_FILES\x10\x04\x12\x17\n\x13PINNED_GUEST_IMAGES\x10\x05\x12\x0c\n\x08\x46IRMWARE\x10\x06\x12\x0f\n\x0b\x45\x42UILD_LOGS\x10\x07\x12\x13\n\x0f\x43HROMEOS_CONFIG\x10\x08\x12\x0e\n\nCPE_REPORT\x10\t\x12\x12\n\x0eIMAGE_ARCHIVES\x10\n\x12\x13\n\x0f\x46PMCU_UNITTESTS\x10\x1b\x12\x0f\n\x0bGCE_TARBALL\x10\x1c\x12\x11\n\rDEBUG_SYMBOLS\x10 \"\x04\x08\x0b\x10\x1a\"\x04\x08\x1d\x10\x1f\"\x04\x08!\x10+\x1a\xff\x07\n\tToolchain\x12N\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x35.chromiumos.ArtifactsByService.Toolchain.ArtifactInfo\x12O\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x35.chromiumos.ArtifactsByService.Toolchain.ArtifactInfo\x1a\xd1\x01\n\x0c\x41rtifactInfo\x12M\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x35.chromiumos.ArtifactsByService.Toolchain.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\t\x12J\n\x11publish_condition\x18\x05 \x01(\x0e\x32/.chromiumos.ArtifactsByService.PublishCondition\"\xfc\x04\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12$\n UNVERIFIED_CHROME_LLVM_ORDERFILE\x10\x0b\x12\"\n\x1eVERIFIED_CHROME_LLVM_ORDERFILE\x10\x0c\x12\x1e\n\x1a\x43HROME_CLANG_WARNINGS_FILE\x10\r\x12\x1c\n\x18UNVERIFIED_LLVM_PGO_FILE\x10\x0e\x12)\n%UNVERIFIED_CHROME_BENCHMARK_AFDO_FILE\x10\x0f\x12\'\n#VERIFIED_CHROME_BENCHMARK_AFDO_FILE\x10\x10\x12!\n\x1dVERIFIED_KERNEL_CWP_AFDO_FILE\x10\x11\x12#\n\x1fUNVERIFIED_KERNEL_CWP_AFDO_FILE\x10\x12\x12#\n\x1fUNVERIFIED_CHROME_CWP_AFDO_FILE\x10\x13\x12!\n\x1dVERIFIED_CHROME_CWP_AFDO_FILE\x10\x14\x12\x1e\n\x1aVERIFIED_RELEASE_AFDO_FILE\x10\x15\x12)\n%UNVERIFIED_CHROME_BENCHMARK_PERF_FILE\x10\x16\x12\x17\n\x13\x43HROME_DEBUG_BINARY\x10\x17\x12\x1a\n\x16TOOLCHAIN_WARNING_LOGS\x10\x18\x12)\n%CHROME_AFDO_PROFILE_FOR_ANDROID_LINUX\x10\x19\x12\x19\n\x15\x43LANG_CRASH_DIAGNOSES\x10\x1a\x12\x17\n\x13\x43OMPILER_RUSAGE_LOG\x10\x1d\"\x04\x08\x01\x10\n\"\x04\x08\x1b\x10\x1c\"\x04\x08\x1e\x10+\x1a\xda\x03\n\x05Image\x12J\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x31.chromiumos.ArtifactsByService.Image.ArtifactInfo\x12K\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x31.chromiumos.ArtifactsByService.Image.ArtifactInfo\x1a\xcd\x01\n\x0c\x41rtifactInfo\x12I\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x31.chromiumos.ArtifactsByService.Image.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\t\x12J\n\x11publish_condition\x18\x05 \x01(\x0e\x32/.chromiumos.ArtifactsByService.PublishCondition\"h\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\r\n\tDLC_IMAGE\x10\"\x12\x13\n\x0fLICENSE_CREDITS\x10&\x12\x11\n\rFACTORY_IMAGE\x10+\"\x04\x08\x01\x10!\"\x04\x08#\x10%\"\x04\x08\'\x10*\x1a\x9f\x03\n\x07Package\x12L\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x33.chromiumos.ArtifactsByService.Package.ArtifactInfo\x12M\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x33.chromiumos.ArtifactsByService.Package.ArtifactInfo\x1a\xcf\x01\n\x0c\x41rtifactInfo\x12K\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x33.chromiumos.ArtifactsByService.Package.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\t\x12J\n\x11publish_condition\x18\x05 \x01(\x0e\x32/.chromiumos.ArtifactsByService.PublishCondition\"%\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\"\x04\x08\x01\x10+\x1a\x8d\x04\n\x07Sysroot\x12L\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x33.chromiumos.ArtifactsByService.Sysroot.ArtifactInfo\x12M\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x33.chromiumos.ArtifactsByService.Sysroot.ArtifactInfo\x1a\xcf\x01\n\x0c\x41rtifactInfo\x12K\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x33.chromiumos.ArtifactsByService.Sysroot.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\t\x12J\n\x11publish_condition\x18\x05 \x01(\x0e\x32/.chromiumos.ArtifactsByService.PublishCondition\"\x92\x01\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x11\n\rDEBUG_SYMBOLS\x10 \x12\x1a\n\x16\x42REAKPAD_DEBUG_SYMBOLS\x10#\x12\x19\n\x15SIMPLE_CHROME_SYSROOT\x10(\x12\x15\n\x11\x43HROME_EBUILD_ENV\x10)\"\x04\x08\x01\x10\x1f\"\x04\x08!\x10\"\"\x04\x08$\x10\'\x1a\xb2\x04\n\x04Test\x12I\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x30.chromiumos.ArtifactsByService.Test.ArtifactInfo\x12J\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x30.chromiumos.ArtifactsByService.Test.ArtifactInfo\x1a\xa6\x02\n\x0c\x41rtifactInfo\x12H\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x30.chromiumos.ArtifactsByService.Test.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\t\x12J\n\x11publish_condition\x18\x05 \x01(\x0e\x32/.chromiumos.ArtifactsByService.PublishCondition\x12X\n\x19\x63ode_coverage_upload_info\x18\x06 \x01(\x0b\x32\x35.chromiumos.ArtifactsByService.CodeCoverageUploadInfo\"j\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x0e\n\nUNIT_TESTS\x10%\x12\x1b\n\x17\x43ODE_COVERAGE_LLVM_JSON\x10\'\x12\n\n\x06HWQUAL\x10*\"\x04\x08\x01\x10$\"\x04\x08&\x10&\"\x04\x08(\x10)\x1a\xf7\x04\n\x08\x46irmware\x12M\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x34.chromiumos.ArtifactsByService.Firmware.ArtifactInfo\x12N\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x34.chromiumos.ArtifactsByService.Firmware.ArtifactInfo\x1a\xd4\x02\n\x0c\x41rtifactInfo\x12L\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x34.chromiumos.ArtifactsByService.Firmware.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\t\x12J\n\x11publish_condition\x18\x05 \x01(\x0e\x32/.chromiumos.ArtifactsByService.PublishCondition\x12(\n\x08location\x18\x06 \x01(\x0e\x32\x16.chromiumos.FwLocation\x12X\n\x19\x63ode_coverage_upload_info\x18\x07 \x01(\x0b\x32\x35.chromiumos.ArtifactsByService.CodeCoverageUploadInfo\"u\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x14\n\x10\x46IRMWARE_TARBALL\x10\x1e\x12\x19\n\x15\x46IRMWARE_TARBALL_INFO\x10\x1f\x12\x11\n\rFIRMWARE_LCOV\x10!\"\x04\x08\x01\x10\x1d\"\x04\x08 \x10 \"\x04\x08\"\x10+\x1a\xb1\x03\n\x05Infra\x12J\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x31.chromiumos.ArtifactsByService.Infra.ArtifactInfo\x12K\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x31.chromiumos.ArtifactsByService.Infra.ArtifactInfo\x1a\xcd\x01\n\x0c\x41rtifactInfo\x12I\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x31.chromiumos.ArtifactsByService.Infra.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\t\x12J\n\x11publish_condition\x18\x05 \x01(\x0e\x32/.chromiumos.ArtifactsByService.PublishCondition\"?\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x12\n\x0e\x42UILD_MANIFEST\x10$\"\x04\x08\x01\x10#\"\x04\x08%\x10+\"W\n\x10PublishCondition\x12\x17\n\x13PUBLISH_UNSPECIFIED\x10\x00\x12\x16\n\x12PUBLISH_ON_SUCCESS\x10\x01\x12\x12\n\x0ePUBLISH_ALWAYS\x10\x02\"\x8e\x12\n\x1aUploadedArtifactsByService\x12=\n\x06legacy\x18\x01 \x01(\x0b\x32-.chromiumos.UploadedArtifactsByService.Legacy\x12\x43\n\ttoolchain\x18\x02 \x01(\x0b\x32\x30.chromiumos.UploadedArtifactsByService.Toolchain\x12;\n\x05image\x18\x03 \x01(\x0b\x32,.chromiumos.UploadedArtifactsByService.Image\x12?\n\x07package\x18\x04 \x01(\x0b\x32..chromiumos.UploadedArtifactsByService.Package\x12?\n\x07sysroot\x18\x05 \x01(\x0b\x32..chromiumos.UploadedArtifactsByService.Sysroot\x12\x39\n\x04test\x18\x06 \x01(\x0b\x32+.chromiumos.UploadedArtifactsByService.Test\x12\x41\n\x08\x66irmware\x18\x07 \x01(\x0b\x32/.chromiumos.UploadedArtifactsByService.Firmware\x12;\n\x05infra\x18\x08 \x01(\x0b\x32,.chromiumos.UploadedArtifactsByService.Infra\x1a\xd5\x01\n\x06Legacy\x12N\n\tartifacts\x18\x01 \x03(\x0b\x32;.chromiumos.UploadedArtifactsByService.Legacy.ArtifactPaths\x1a{\n\rArtifactPaths\x12I\n\rartifact_type\x18\x01 \x01(\x0e\x32\x32.chromiumos.ArtifactsByService.Legacy.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path\x1a\xde\x01\n\tToolchain\x12Q\n\tartifacts\x18\x01 \x03(\x0b\x32>.chromiumos.UploadedArtifactsByService.Toolchain.ArtifactPaths\x1a~\n\rArtifactPaths\x12L\n\rartifact_type\x18\x01 \x01(\x0e\x32\x35.chromiumos.ArtifactsByService.Toolchain.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path\x1a\xd2\x01\n\x05Image\x12M\n\tartifacts\x18\x01 \x03(\x0b\x32:.chromiumos.UploadedArtifactsByService.Image.ArtifactPaths\x1az\n\rArtifactPaths\x12H\n\rartifact_type\x18\x01 \x01(\x0e\x32\x31.chromiumos.ArtifactsByService.Image.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path\x1a\xd8\x01\n\x07Package\x12O\n\tartifacts\x18\x01 \x03(\x0b\x32<.chromiumos.UploadedArtifactsByService.Package.ArtifactPaths\x1a|\n\rArtifactPaths\x12J\n\rartifact_type\x18\x01 \x01(\x0e\x32\x33.chromiumos.ArtifactsByService.Package.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path\x1a\xd8\x01\n\x07Sysroot\x12O\n\tartifacts\x18\x01 \x03(\x0b\x32<.chromiumos.UploadedArtifactsByService.Sysroot.ArtifactPaths\x1a|\n\rArtifactPaths\x12J\n\rartifact_type\x18\x01 \x01(\x0e\x32\x33.chromiumos.ArtifactsByService.Sysroot.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path\x1a\xcf\x01\n\x04Test\x12L\n\tartifacts\x18\x01 \x03(\x0b\x32\x39.chromiumos.UploadedArtifactsByService.Test.ArtifactPaths\x1ay\n\rArtifactPaths\x12G\n\rartifact_type\x18\x01 \x01(\x0e\x32\x30.chromiumos.ArtifactsByService.Test.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path\x1a\x86\x02\n\x08\x46irmware\x12P\n\tartifacts\x18\x01 \x03(\x0b\x32=.chromiumos.UploadedArtifactsByService.Firmware.ArtifactPaths\x1a\xa7\x01\n\rArtifactPaths\x12K\n\rartifact_type\x18\x01 \x01(\x0e\x32\x34.chromiumos.ArtifactsByService.Firmware.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path\x12(\n\x08location\x18\x03 \x01(\x0e\x32\x16.chromiumos.FwLocation\x1a\xd2\x01\n\x05Infra\x12M\n\tartifacts\x18\x01 \x03(\x0b\x32:.chromiumos.UploadedArtifactsByService.Infra.ArtifactPaths\x1az\n\rArtifactPaths\x12H\n\rartifact_type\x18\x01 \x01(\x0e\x32\x31.chromiumos.ArtifactsByService.Infra.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path*\xca\x04\n\tImageType\x12\x18\n\x14IMAGE_TYPE_UNDEFINED\x10\x00\x12\x13\n\x0fIMAGE_TYPE_BASE\x10\x01\x12\x12\n\x0eIMAGE_TYPE_DEV\x10\x02\x12\x13\n\x0fIMAGE_TYPE_TEST\x10\x03\x12\x16\n\x12IMAGE_TYPE_BASE_VM\x10\x04\x12\x16\n\x12IMAGE_TYPE_TEST_VM\x10\x05\x12\x17\n\x13IMAGE_TYPE_RECOVERY\x10\x06\x12\x16\n\x12IMAGE_TYPE_FACTORY\x10\x07\x12\x17\n\x13IMAGE_TYPE_FIRMWARE\x10\x08\x12\x1c\n\x18IMAGE_TYPE_CR50_FIRMWARE\x10\t\x12\x1c\n\x18IMAGE_TYPE_BASE_GUEST_VM\x10\n\x12\x1c\n\x18IMAGE_TYPE_TEST_GUEST_VM\x10\x0b\x12\x12\n\x0eIMAGE_TYPE_DLC\x10\x0c\x12\x1b\n\x17IMAGE_TYPE_GSC_FIRMWARE\x10\r\x12\x1e\n\x1aIMAGE_TYPE_ACCESSORY_USBPD\x10\x0e\x12\x1e\n\x1aIMAGE_TYPE_ACCESSORY_RWSIG\x10\x0f*\x04\x42\x41SE*\x04TEST*\x03\x44\x45V*\x07\x42\x41SE_VM*\x07TEST_VM*\x08RECOVERY*\x07\x46\x41\x43TORY*\x08\x46IRMWARE*\rCR50_FIRMWARE*\rBASE_GUEST_VM*\rTEST_GUEST_VM*\x03\x44LC*\x0cGSC_FIRMWARE*\x0f\x41\x43\x43\x45SSORY_USBPD*\x0f\x41\x43\x43\x45SSORY_RWSIG*\x80\x01\n\x07\x43hannel\x12\x17\n\x13\x43HANNEL_UNSPECIFIED\x10\x00\x12\x12\n\x0e\x43HANNEL_STABLE\x10\x01\x12\x10\n\x0c\x43HANNEL_BETA\x10\x02\x12\x0f\n\x0b\x43HANNEL_DEV\x10\x03\x12\x12\n\x0e\x43HANNEL_CANARY\x10\x04\x12\x11\n\rCHANNEL_RUBIK\x10\x05*l\n\tDeltaType\x12\x11\n\rDELTA_UNKNOWN\x10\x00\x12\x0c\n\x08NO_DELTA\x10\x01\x12\x07\n\x03\x46SI\x10\x02\x12\r\n\tMILESTONE\x10\x03\x12\t\n\x05OMAHA\x10\x04\x12\x12\n\x0eSTEPPING_STONE\x10\x05\x12\x07\n\x03N2N\x10\x06*^\n\nFwLocation\x12\x17\n\x13\x46W_LOCATION_UNKNOWN\x10\x00\x12\x0f\n\x0bPLATFORM_EC\x10\x01\x12\x13\n\x0fPLATFORM_ZEPHYR\x10\x02\x12\x11\n\rPLATFORM_TI50\x10\x03*f\n\x10\x41\x46\x44OArtifactType\x12\r\n\tNONE_TYPE\x10\x00\x12\r\n\tORDERFILE\x10\x01\x12\x12\n\x0e\x42\x45NCHMARK_AFDO\x10\x02\x12\x0f\n\x0bKERNEL_AFDO\x10\x03\x12\x0f\n\x0b\x43HROME_AFDO\x10\x04\x42Y\n!com.google.chrome.crosinfra.protoZ4go.chromium.org/chromiumos/infra/proto/go/chromiumosb\x06proto3'
+  serialized_pb=b'\n\x17\x63hromiumos/common.proto\x12\nchromiumos\"\x1b\n\x0b\x42uildTarget\x12\x0c\n\x04name\x18\x01 \x01(\t\"\'\n\x07GcsPath\x12\x0e\n\x06\x62ucket\x18\x01 \x01(\t\x12\x0c\n\x04path\x18\x02 \x01(\t\"\xd0\x01\n\x06\x43hroot\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x11\n\tcache_dir\x18\x02 \x01(\t\x12)\n\x03\x65nv\x18\x03 \x01(\x0b\x32\x1c.chromiumos.Chroot.ChrootEnv\x12\x12\n\nchrome_dir\x18\x04 \x01(\t\x1aZ\n\tChrootEnv\x12&\n\tuse_flags\x18\x01 \x03(\x0b\x32\x13.chromiumos.UseFlag\x12%\n\x08\x66\x65\x61tures\x18\x02 \x03(\x0b\x32\x13.chromiumos.FeatureJ\x04\x08\x05\x10\x06R\x04goma\"\x1a\n\x07\x46\x65\x61ture\x12\x0f\n\x07\x66\x65\x61ture\x18\x01 \x01(\t\"B\n\x10RemoteexecConfig\x12\x14\n\x0creclient_dir\x18\x01 \x01(\t\x12\x18\n\x10reproxy_cfg_file\x18\x02 \x01(\t\"\xcf\x02\n\nGomaConfig\x12\x10\n\x08goma_dir\x18\x01 \x01(\t\x12\x18\n\x10goma_client_json\x18\x02 \x01(\t\x12\x19\n\x11\x63hromeos_goma_dir\x18\x03 \x01(\t\x12:\n\rgoma_approach\x18\x04 \x01(\x0e\x32#.chromiumos.GomaConfig.GomaApproach\x12&\n\x07log_dir\x18\x05 \x01(\x0b\x32\x15.chromiumos.SyncedDir\x12\x12\n\nstats_file\x18\x06 \x01(\t\x12\x15\n\rcounterz_file\x18\x07 \x01(\t\"k\n\x0cGomaApproach\x12\x1d\n\x19GOMA_APPROACH_UNSPECIFIED\x10\x00\x12\x0b\n\x07\x44\x45\x46\x41ULT\x10\x01\x12\x0c\n\x08RBE_PROD\x10\x02\x12\x0f\n\x0bRBE_STAGING\x10\x03\x12\x10\n\x0cRBE_CHROMEOS\x10\x04\"M\n\rGomaArtifacts\x12\x12\n\nstats_file\x18\x01 \x01(\t\x12\x15\n\rcounterz_file\x18\x02 \x01(\t\x12\x11\n\tlog_files\x18\x03 \x03(\t\"F\n\x0bPackageInfo\x12\x14\n\x0cpackage_name\x18\x01 \x01(\t\x12\x10\n\x08\x63\x61tegory\x18\x02 \x01(\t\x12\x0f\n\x07version\x18\x03 \x01(\t\"\x17\n\x07Profile\x12\x0c\n\x04name\x18\x01 \x01(\t\"\xa8\x01\n\x10PackageIndexInfo\x12\x14\n\x0csnapshot_sha\x18\x01 \x01(\t\x12\x17\n\x0fsnapshot_number\x18\x02 \x01(\x05\x12-\n\x0c\x62uild_target\x18\x03 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x12\x10\n\x08location\x18\x04 \x01(\t\x12$\n\x07profile\x18\x05 \x01(\x0b\x32\x13.chromiumos.Profile\"w\n\x04Path\x12\x0c\n\x04path\x18\x01 \x01(\t\x12+\n\x08location\x18\x02 \x01(\x0e\x32\x19.chromiumos.Path.Location\"4\n\x08Location\x12\x0f\n\x0bNO_LOCATION\x10\x00\x12\n\n\x06INSIDE\x10\x01\x12\x0b\n\x07OUTSIDE\x10\x02\",\n\nResultPath\x12\x1e\n\x04path\x18\x01 \x01(\x0b\x32\x10.chromiumos.Path\"\x18\n\tSyncedDir\x12\x0b\n\x03\x64ir\x18\x01 \x01(\t\"O\n\x0cGerritChange\x12\x0c\n\x04host\x18\x01 \x01(\t\x12\x0f\n\x07project\x18\x02 \x01(\t\x12\x0e\n\x06\x63hange\x18\x03 \x01(\x03\x12\x10\n\x08patchset\x18\x04 \x01(\x03\"Y\n\rGitilesCommit\x12\x0c\n\x04host\x18\x01 \x01(\t\x12\x0f\n\x07project\x18\x02 \x01(\t\x12\n\n\x02id\x18\x03 \x01(\t\x12\x0b\n\x03ref\x18\x04 \x01(\t\x12\x10\n\x08position\x18\x05 \x01(\r\"\x17\n\x07UseFlag\x12\x0c\n\x04\x66lag\x18\x01 \x01(\t\"\xb8\x02\n\x0eReleaseBuilder\x12\x39\n\tmilestone\x18\x01 \x01(\x0b\x32$.chromiumos.ReleaseBuilder.MilestoneH\x00\x12\x16\n\x0e\x62uild_schedule\x18\x02 \x01(\t\x12\x38\n\x0f\x65xpiration_date\x18\x03 \x01(\x0b\x32\x1f.chromiumos.ReleaseBuilder.Date\x1a\x15\n\x04\x44\x61te\x12\r\n\x05value\x18\x01 \x01(\t\x1am\n\tMilestone\x12\x0e\n\x06number\x18\x01 \x01(\x05\x12;\n\x12target_branch_date\x18\x02 \x01(\x0b\x32\x1f.chromiumos.ReleaseBuilder.Date\x12\x13\n\x0b\x62ranch_name\x18\x03 \x01(\tB\x13\n\x11milestone_message\"?\n\x0fReleaseBuilders\x12,\n\x08\x62uilders\x18\x01 \x03(\x0b\x32\x1a.chromiumos.ReleaseBuilder\"\xf4\x01\n\x0fReleaseChannels\x12J\n\x10release_channels\x18\x01 \x03(\x0b\x32\x30.chromiumos.ReleaseChannels.ReleaseChannelsEntry\x1a\x34\n\x0b\x43hannelList\x12%\n\x08\x63hannels\x18\x01 \x03(\x0e\x32\x13.chromiumos.Channel\x1a_\n\x14ReleaseChannelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\x36\n\x05value\x18\x02 \x01(\x0b\x32\'.chromiumos.ReleaseChannels.ChannelList:\x02\x38\x01\"&\n\nProtoBytes\x12\x18\n\x10serialized_proto\x18\x01 \x01(\x0c\"q\n\x1dPrepareForBuildAdditionalArgs\x12\x1c\n\x12\x63hrome_cwp_profile\x18\x01 \x01(\tH\x00\x12\x18\n\x0ekernel_version\x18\x02 \x01(\tH\x00\x42\x18\n\x16prepare_for_build_args\"A\n\x0b\x41\x66\x64oRelease\x12\x1a\n\x12\x63hrome_cwp_profile\x18\x01 \x01(\t\x12\x16\n\x0eimage_build_id\x18\x02 \x01(\x03\"\x97\x01\n\x13\x41rtifactProfileInfo\x12\x1c\n\x12\x63hrome_cwp_profile\x18\x01 \x01(\tH\x00\x12\x18\n\x0ekernel_version\x18\x02 \x01(\tH\x00\x12/\n\x0c\x61\x66\x64o_release\x18\x03 \x01(\x0b\x32\x17.chromiumos.AfdoReleaseH\x00\x42\x17\n\x15\x61rtifact_profile_info\"\xb5&\n\x12\x41rtifactsByService\x12\x35\n\x06legacy\x18\x01 \x01(\x0b\x32%.chromiumos.ArtifactsByService.Legacy\x12;\n\ttoolchain\x18\x02 \x01(\x0b\x32(.chromiumos.ArtifactsByService.Toolchain\x12\x33\n\x05image\x18\x03 \x01(\x0b\x32$.chromiumos.ArtifactsByService.Image\x12\x37\n\x07package\x18\x04 \x01(\x0b\x32&.chromiumos.ArtifactsByService.Package\x12\x37\n\x07sysroot\x18\x05 \x01(\x0b\x32&.chromiumos.ArtifactsByService.Sysroot\x12\x31\n\x04test\x18\x06 \x01(\x0b\x32#.chromiumos.ArtifactsByService.Test\x12\x35\n\x0cprofile_info\x18\x07 \x01(\x0b\x32\x1f.chromiumos.ArtifactProfileInfo\x12\x39\n\x08\x66irmware\x18\x08 \x01(\x0b\x32\'.chromiumos.ArtifactsByService.Firmware\x12\x33\n\x05infra\x18\t \x01(\x0b\x32$.chromiumos.ArtifactsByService.Infra\x1a\xb0\x01\n\x16\x43odeCoverageUploadInfo\x12]\n\rcoverage_type\x18\x01 \x01(\x0e\x32\x46.chromiumos.ArtifactsByService.CodeCoverageUploadInfo.CodeCoverageType\"7\n\x10\x43odeCoverageType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x08\n\x04LLVM\x10\x01\x12\x08\n\x04LCOV\x10\x02\x1a\xec\x04\n\x06Legacy\x12K\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x32.chromiumos.ArtifactsByService.Legacy.ArtifactInfo\x12L\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x32.chromiumos.ArtifactsByService.Legacy.ArtifactInfo\x1a\x9c\x01\n\x0c\x41rtifactInfo\x12J\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x32.chromiumos.ArtifactsByService.Legacy.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\tJ\x04\x08\x03\x10\x04J\x04\x08\x05\x10\x06R\x0cprofile_info\"\xa7\x02\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\r\n\tIMAGE_ZIP\x10\x01\x12\x17\n\x13TEST_UPDATE_PAYLOAD\x10\x02\x12\x12\n\x0e\x41UTOTEST_FILES\x10\x03\x12\x0e\n\nTAST_FILES\x10\x04\x12\x17\n\x13PINNED_GUEST_IMAGES\x10\x05\x12\x0c\n\x08\x46IRMWARE\x10\x06\x12\x0f\n\x0b\x45\x42UILD_LOGS\x10\x07\x12\x13\n\x0f\x43HROMEOS_CONFIG\x10\x08\x12\x0e\n\nCPE_REPORT\x10\t\x12\x12\n\x0eIMAGE_ARCHIVES\x10\n\x12\x13\n\x0f\x46PMCU_UNITTESTS\x10\x1b\x12\x0f\n\x0bGCE_TARBALL\x10\x1c\x12\x11\n\rDEBUG_SYMBOLS\x10 \"\x04\x08\x0b\x10\x1a\"\x04\x08\x1d\x10\x1f\"\x04\x08!\x10+\x1a\xb9\x07\n\tToolchain\x12N\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x35.chromiumos.ArtifactsByService.Toolchain.ArtifactInfo\x12O\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x35.chromiumos.ArtifactsByService.Toolchain.ArtifactInfo\x1a\x8b\x01\n\x0c\x41rtifactInfo\x12M\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x35.chromiumos.ArtifactsByService.Toolchain.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\tJ\x04\x08\x05\x10\x06\"\xfc\x04\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12$\n UNVERIFIED_CHROME_LLVM_ORDERFILE\x10\x0b\x12\"\n\x1eVERIFIED_CHROME_LLVM_ORDERFILE\x10\x0c\x12\x1e\n\x1a\x43HROME_CLANG_WARNINGS_FILE\x10\r\x12\x1c\n\x18UNVERIFIED_LLVM_PGO_FILE\x10\x0e\x12)\n%UNVERIFIED_CHROME_BENCHMARK_AFDO_FILE\x10\x0f\x12\'\n#VERIFIED_CHROME_BENCHMARK_AFDO_FILE\x10\x10\x12!\n\x1dVERIFIED_KERNEL_CWP_AFDO_FILE\x10\x11\x12#\n\x1fUNVERIFIED_KERNEL_CWP_AFDO_FILE\x10\x12\x12#\n\x1fUNVERIFIED_CHROME_CWP_AFDO_FILE\x10\x13\x12!\n\x1dVERIFIED_CHROME_CWP_AFDO_FILE\x10\x14\x12\x1e\n\x1aVERIFIED_RELEASE_AFDO_FILE\x10\x15\x12)\n%UNVERIFIED_CHROME_BENCHMARK_PERF_FILE\x10\x16\x12\x17\n\x13\x43HROME_DEBUG_BINARY\x10\x17\x12\x1a\n\x16TOOLCHAIN_WARNING_LOGS\x10\x18\x12)\n%CHROME_AFDO_PROFILE_FOR_ANDROID_LINUX\x10\x19\x12\x19\n\x15\x43LANG_CRASH_DIAGNOSES\x10\x1a\x12\x17\n\x13\x43OMPILER_RUSAGE_LOG\x10\x1d\"\x04\x08\x01\x10\n\"\x04\x08\x1b\x10\x1c\"\x04\x08\x1e\x10+\x1a\x94\x03\n\x05Image\x12J\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x31.chromiumos.ArtifactsByService.Image.ArtifactInfo\x12K\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x31.chromiumos.ArtifactsByService.Image.ArtifactInfo\x1a\x87\x01\n\x0c\x41rtifactInfo\x12I\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x31.chromiumos.ArtifactsByService.Image.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\tJ\x04\x08\x05\x10\x06\"h\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\r\n\tDLC_IMAGE\x10\"\x12\x13\n\x0fLICENSE_CREDITS\x10&\x12\x11\n\rFACTORY_IMAGE\x10+\"\x04\x08\x01\x10!\"\x04\x08#\x10%\"\x04\x08\'\x10*\x1a\xd9\x02\n\x07Package\x12L\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x33.chromiumos.ArtifactsByService.Package.ArtifactInfo\x12M\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x33.chromiumos.ArtifactsByService.Package.ArtifactInfo\x1a\x89\x01\n\x0c\x41rtifactInfo\x12K\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x33.chromiumos.ArtifactsByService.Package.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\tJ\x04\x08\x05\x10\x06\"%\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\"\x04\x08\x01\x10+\x1a\xc7\x03\n\x07Sysroot\x12L\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x33.chromiumos.ArtifactsByService.Sysroot.ArtifactInfo\x12M\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x33.chromiumos.ArtifactsByService.Sysroot.ArtifactInfo\x1a\x89\x01\n\x0c\x41rtifactInfo\x12K\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x33.chromiumos.ArtifactsByService.Sysroot.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\tJ\x04\x08\x05\x10\x06\"\x92\x01\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x11\n\rDEBUG_SYMBOLS\x10 \x12\x1a\n\x16\x42REAKPAD_DEBUG_SYMBOLS\x10#\x12\x19\n\x15SIMPLE_CHROME_SYSROOT\x10(\x12\x15\n\x11\x43HROME_EBUILD_ENV\x10)\"\x04\x08\x01\x10\x1f\"\x04\x08!\x10\"\"\x04\x08$\x10\'\x1a\xec\x03\n\x04Test\x12I\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x30.chromiumos.ArtifactsByService.Test.ArtifactInfo\x12J\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x30.chromiumos.ArtifactsByService.Test.ArtifactInfo\x1a\xe0\x01\n\x0c\x41rtifactInfo\x12H\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x30.chromiumos.ArtifactsByService.Test.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\t\x12X\n\x19\x63ode_coverage_upload_info\x18\x06 \x01(\x0b\x32\x35.chromiumos.ArtifactsByService.CodeCoverageUploadInfoJ\x04\x08\x05\x10\x06\"j\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x0e\n\nUNIT_TESTS\x10%\x12\x1b\n\x17\x43ODE_COVERAGE_LLVM_JSON\x10\'\x12\n\n\x06HWQUAL\x10*\"\x04\x08\x01\x10$\"\x04\x08&\x10&\"\x04\x08(\x10)\x1a\xb1\x04\n\x08\x46irmware\x12M\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x34.chromiumos.ArtifactsByService.Firmware.ArtifactInfo\x12N\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x34.chromiumos.ArtifactsByService.Firmware.ArtifactInfo\x1a\x8e\x02\n\x0c\x41rtifactInfo\x12L\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x34.chromiumos.ArtifactsByService.Firmware.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\t\x12(\n\x08location\x18\x06 \x01(\x0e\x32\x16.chromiumos.FwLocation\x12X\n\x19\x63ode_coverage_upload_info\x18\x07 \x01(\x0b\x32\x35.chromiumos.ArtifactsByService.CodeCoverageUploadInfoJ\x04\x08\x05\x10\x06\"u\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x14\n\x10\x46IRMWARE_TARBALL\x10\x1e\x12\x19\n\x15\x46IRMWARE_TARBALL_INFO\x10\x1f\x12\x11\n\rFIRMWARE_LCOV\x10!\"\x04\x08\x01\x10\x1d\"\x04\x08 \x10 \"\x04\x08\"\x10+\x1a\xeb\x02\n\x05Infra\x12J\n\x0finput_artifacts\x18\x01 \x03(\x0b\x32\x31.chromiumos.ArtifactsByService.Infra.ArtifactInfo\x12K\n\x10output_artifacts\x18\x02 \x03(\x0b\x32\x31.chromiumos.ArtifactsByService.Infra.ArtifactInfo\x1a\x87\x01\n\x0c\x41rtifactInfo\x12I\n\x0e\x61rtifact_types\x18\x01 \x03(\x0e\x32\x31.chromiumos.ArtifactsByService.Infra.ArtifactType\x12\x14\n\x0cgs_locations\x18\x02 \x03(\t\x12\x10\n\x08\x61\x63l_name\x18\x04 \x01(\tJ\x04\x08\x05\x10\x06\"?\n\x0c\x41rtifactType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x12\n\x0e\x42UILD_MANIFEST\x10$\"\x04\x08\x01\x10#\"\x04\x08%\x10+\"\x8e\x12\n\x1aUploadedArtifactsByService\x12=\n\x06legacy\x18\x01 \x01(\x0b\x32-.chromiumos.UploadedArtifactsByService.Legacy\x12\x43\n\ttoolchain\x18\x02 \x01(\x0b\x32\x30.chromiumos.UploadedArtifactsByService.Toolchain\x12;\n\x05image\x18\x03 \x01(\x0b\x32,.chromiumos.UploadedArtifactsByService.Image\x12?\n\x07package\x18\x04 \x01(\x0b\x32..chromiumos.UploadedArtifactsByService.Package\x12?\n\x07sysroot\x18\x05 \x01(\x0b\x32..chromiumos.UploadedArtifactsByService.Sysroot\x12\x39\n\x04test\x18\x06 \x01(\x0b\x32+.chromiumos.UploadedArtifactsByService.Test\x12\x41\n\x08\x66irmware\x18\x07 \x01(\x0b\x32/.chromiumos.UploadedArtifactsByService.Firmware\x12;\n\x05infra\x18\x08 \x01(\x0b\x32,.chromiumos.UploadedArtifactsByService.Infra\x1a\xd5\x01\n\x06Legacy\x12N\n\tartifacts\x18\x01 \x03(\x0b\x32;.chromiumos.UploadedArtifactsByService.Legacy.ArtifactPaths\x1a{\n\rArtifactPaths\x12I\n\rartifact_type\x18\x01 \x01(\x0e\x32\x32.chromiumos.ArtifactsByService.Legacy.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path\x1a\xde\x01\n\tToolchain\x12Q\n\tartifacts\x18\x01 \x03(\x0b\x32>.chromiumos.UploadedArtifactsByService.Toolchain.ArtifactPaths\x1a~\n\rArtifactPaths\x12L\n\rartifact_type\x18\x01 \x01(\x0e\x32\x35.chromiumos.ArtifactsByService.Toolchain.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path\x1a\xd2\x01\n\x05Image\x12M\n\tartifacts\x18\x01 \x03(\x0b\x32:.chromiumos.UploadedArtifactsByService.Image.ArtifactPaths\x1az\n\rArtifactPaths\x12H\n\rartifact_type\x18\x01 \x01(\x0e\x32\x31.chromiumos.ArtifactsByService.Image.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path\x1a\xd8\x01\n\x07Package\x12O\n\tartifacts\x18\x01 \x03(\x0b\x32<.chromiumos.UploadedArtifactsByService.Package.ArtifactPaths\x1a|\n\rArtifactPaths\x12J\n\rartifact_type\x18\x01 \x01(\x0e\x32\x33.chromiumos.ArtifactsByService.Package.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path\x1a\xd8\x01\n\x07Sysroot\x12O\n\tartifacts\x18\x01 \x03(\x0b\x32<.chromiumos.UploadedArtifactsByService.Sysroot.ArtifactPaths\x1a|\n\rArtifactPaths\x12J\n\rartifact_type\x18\x01 \x01(\x0e\x32\x33.chromiumos.ArtifactsByService.Sysroot.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path\x1a\xcf\x01\n\x04Test\x12L\n\tartifacts\x18\x01 \x03(\x0b\x32\x39.chromiumos.UploadedArtifactsByService.Test.ArtifactPaths\x1ay\n\rArtifactPaths\x12G\n\rartifact_type\x18\x01 \x01(\x0e\x32\x30.chromiumos.ArtifactsByService.Test.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path\x1a\x86\x02\n\x08\x46irmware\x12P\n\tartifacts\x18\x01 \x03(\x0b\x32=.chromiumos.UploadedArtifactsByService.Firmware.ArtifactPaths\x1a\xa7\x01\n\rArtifactPaths\x12K\n\rartifact_type\x18\x01 \x01(\x0e\x32\x34.chromiumos.ArtifactsByService.Firmware.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path\x12(\n\x08location\x18\x03 \x01(\x0e\x32\x16.chromiumos.FwLocation\x1a\xd2\x01\n\x05Infra\x12M\n\tartifacts\x18\x01 \x03(\x0b\x32:.chromiumos.UploadedArtifactsByService.Infra.ArtifactPaths\x1az\n\rArtifactPaths\x12H\n\rartifact_type\x18\x01 \x01(\x0e\x32\x31.chromiumos.ArtifactsByService.Infra.ArtifactType\x12\x1f\n\x05paths\x18\x02 \x03(\x0b\x32\x10.chromiumos.Path*\xf5\x04\n\tImageType\x12\x18\n\x14IMAGE_TYPE_UNDEFINED\x10\x00\x12\x13\n\x0fIMAGE_TYPE_BASE\x10\x01\x12\x12\n\x0eIMAGE_TYPE_DEV\x10\x02\x12\x13\n\x0fIMAGE_TYPE_TEST\x10\x03\x12\x16\n\x12IMAGE_TYPE_BASE_VM\x10\x04\x12\x16\n\x12IMAGE_TYPE_TEST_VM\x10\x05\x12\x17\n\x13IMAGE_TYPE_RECOVERY\x10\x06\x12\x16\n\x12IMAGE_TYPE_FACTORY\x10\x07\x12\x17\n\x13IMAGE_TYPE_FIRMWARE\x10\x08\x12\x1c\n\x18IMAGE_TYPE_CR50_FIRMWARE\x10\t\x12\x1c\n\x18IMAGE_TYPE_BASE_GUEST_VM\x10\n\x12\x1c\n\x18IMAGE_TYPE_TEST_GUEST_VM\x10\x0b\x12\x12\n\x0eIMAGE_TYPE_DLC\x10\x0c\x12\x1b\n\x17IMAGE_TYPE_GSC_FIRMWARE\x10\r\x12\x1e\n\x1aIMAGE_TYPE_ACCESSORY_USBPD\x10\x0e\x12\x1e\n\x1aIMAGE_TYPE_ACCESSORY_RWSIG\x10\x0f\x12\x1b\n\x17IMAGE_TYPE_HPS_FIRMWARE\x10\x10*\x04\x42\x41SE*\x04TEST*\x03\x44\x45V*\x07\x42\x41SE_VM*\x07TEST_VM*\x08RECOVERY*\x07\x46\x41\x43TORY*\x08\x46IRMWARE*\rCR50_FIRMWARE*\rBASE_GUEST_VM*\rTEST_GUEST_VM*\x03\x44LC*\x0cGSC_FIRMWARE*\x0f\x41\x43\x43\x45SSORY_USBPD*\x0f\x41\x43\x43\x45SSORY_RWSIG*\x0cHPS_FIRMWARE*\x80\x01\n\x07\x43hannel\x12\x17\n\x13\x43HANNEL_UNSPECIFIED\x10\x00\x12\x12\n\x0e\x43HANNEL_STABLE\x10\x01\x12\x10\n\x0c\x43HANNEL_BETA\x10\x02\x12\x0f\n\x0b\x43HANNEL_DEV\x10\x03\x12\x12\n\x0e\x43HANNEL_CANARY\x10\x04\x12\x11\n\rCHANNEL_RUBIK\x10\x05*l\n\tDeltaType\x12\x11\n\rDELTA_UNKNOWN\x10\x00\x12\x0c\n\x08NO_DELTA\x10\x01\x12\x07\n\x03\x46SI\x10\x02\x12\r\n\tMILESTONE\x10\x03\x12\t\n\x05OMAHA\x10\x04\x12\x12\n\x0eSTEPPING_STONE\x10\x05\x12\x07\n\x03N2N\x10\x06*q\n\nFwLocation\x12\x17\n\x13\x46W_LOCATION_UNKNOWN\x10\x00\x12\x0f\n\x0bPLATFORM_EC\x10\x01\x12\x13\n\x0fPLATFORM_ZEPHYR\x10\x02\x12\x11\n\rPLATFORM_TI50\x10\x03\x12\x11\n\rPLATFORM_CR50\x10\x04\x42Y\n!com.google.chrome.crosinfra.protoZ4go.chromium.org/chromiumos/infra/proto/go/chromiumosb\x06proto3'
 )
 
 _IMAGETYPE = _descriptor.EnumDescriptor(
@@ -92,11 +92,15 @@
       name='IMAGE_TYPE_ACCESSORY_RWSIG', index=15, number=15,
       serialized_options=None,
       type=None),
+    _descriptor.EnumValueDescriptor(
+      name='IMAGE_TYPE_HPS_FIRMWARE', index=16, number=16,
+      serialized_options=None,
+      type=None),
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=10317,
-  serialized_end=10903,
+  serialized_start=9736,
+  serialized_end=10365,
 )
 _sym_db.RegisterEnumDescriptor(_IMAGETYPE)
 
@@ -134,8 +138,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=10906,
-  serialized_end=11034,
+  serialized_start=10368,
+  serialized_end=10496,
 )
 _sym_db.RegisterEnumDescriptor(_CHANNEL)
 
@@ -177,8 +181,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=11036,
-  serialized_end=11144,
+  serialized_start=10498,
+  serialized_end=10606,
 )
 _sym_db.RegisterEnumDescriptor(_DELTATYPE)
 
@@ -205,50 +209,19 @@
       name='PLATFORM_TI50', index=3, number=3,
       serialized_options=None,
       type=None),
+    _descriptor.EnumValueDescriptor(
+      name='PLATFORM_CR50', index=4, number=4,
+      serialized_options=None,
+      type=None),
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=11146,
-  serialized_end=11240,
+  serialized_start=10608,
+  serialized_end=10721,
 )
 _sym_db.RegisterEnumDescriptor(_FWLOCATION)
 
 FwLocation = enum_type_wrapper.EnumTypeWrapper(_FWLOCATION)
-_AFDOARTIFACTTYPE = _descriptor.EnumDescriptor(
-  name='AFDOArtifactType',
-  full_name='chromiumos.AFDOArtifactType',
-  filename=None,
-  file=DESCRIPTOR,
-  values=[
-    _descriptor.EnumValueDescriptor(
-      name='NONE_TYPE', index=0, number=0,
-      serialized_options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='ORDERFILE', index=1, number=1,
-      serialized_options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='BENCHMARK_AFDO', index=2, number=2,
-      serialized_options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='KERNEL_AFDO', index=3, number=3,
-      serialized_options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='CHROME_AFDO', index=4, number=4,
-      serialized_options=None,
-      type=None),
-  ],
-  containing_type=None,
-  serialized_options=None,
-  serialized_start=11242,
-  serialized_end=11344,
-)
-_sym_db.RegisterEnumDescriptor(_AFDOARTIFACTTYPE)
-
-AFDOArtifactType = enum_type_wrapper.EnumTypeWrapper(_AFDOARTIFACTTYPE)
 IMAGE_TYPE_UNDEFINED = 0
 IMAGE_TYPE_BASE = 1
 IMAGE_TYPE_DEV = 2
@@ -265,6 +238,7 @@
 IMAGE_TYPE_GSC_FIRMWARE = 13
 IMAGE_TYPE_ACCESSORY_USBPD = 14
 IMAGE_TYPE_ACCESSORY_RWSIG = 15
+IMAGE_TYPE_HPS_FIRMWARE = 16
 CHANNEL_UNSPECIFIED = 0
 CHANNEL_STABLE = 1
 CHANNEL_BETA = 2
@@ -282,11 +256,7 @@
 PLATFORM_EC = 1
 PLATFORM_ZEPHYR = 2
 PLATFORM_TI50 = 3
-NONE_TYPE = 0
-ORDERFILE = 1
-BENCHMARK_AFDO = 2
-KERNEL_AFDO = 3
-CHROME_AFDO = 4
+PLATFORM_CR50 = 4
 
 
 _GOMACONFIG_GOMAAPPROACH = _descriptor.EnumDescriptor(
@@ -318,8 +288,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=577,
-  serialized_end=684,
+  serialized_start=645,
+  serialized_end=752,
 )
 _sym_db.RegisterEnumDescriptor(_GOMACONFIG_GOMAAPPROACH)
 
@@ -344,8 +314,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1100,
-  serialized_end=1152,
+  serialized_start=1168,
+  serialized_end=1220,
 )
 _sym_db.RegisterEnumDescriptor(_PATH_LOCATION)
 
@@ -370,8 +340,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=3072,
-  serialized_end=3127,
+  serialized_start=3140,
+  serialized_end=3195,
 )
 _sym_db.RegisterEnumDescriptor(_ARTIFACTSBYSERVICE_CODECOVERAGEUPLOADINFO_CODECOVERAGETYPE)
 
@@ -440,8 +410,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=3525,
-  serialized_end=3820,
+  serialized_start=3523,
+  serialized_end=3818,
 )
 _sym_db.RegisterEnumDescriptor(_ARTIFACTSBYSERVICE_LEGACY_ARTIFACTTYPE)
 
@@ -526,8 +496,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=4210,
-  serialized_end=4846,
+  serialized_start=4138,
+  serialized_end=4774,
 )
 _sym_db.RegisterEnumDescriptor(_ARTIFACTSBYSERVICE_TOOLCHAIN_ARTIFACTTYPE)
 
@@ -556,8 +526,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=5219,
-  serialized_end=5323,
+  serialized_start=5077,
+  serialized_end=5181,
 )
 _sym_db.RegisterEnumDescriptor(_ARTIFACTSBYSERVICE_IMAGE_ARTIFACTTYPE)
 
@@ -574,8 +544,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=5704,
-  serialized_end=5741,
+  serialized_start=5492,
+  serialized_end=5529,
 )
 _sym_db.RegisterEnumDescriptor(_ARTIFACTSBYSERVICE_PACKAGE_ARTIFACTTYPE)
 
@@ -608,8 +578,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=6123,
-  serialized_end=6269,
+  serialized_start=5841,
+  serialized_end=5987,
 )
 _sym_db.RegisterEnumDescriptor(_ARTIFACTSBYSERVICE_SYSROOT_ARTIFACTTYPE)
 
@@ -638,8 +608,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=6728,
-  serialized_end=6834,
+  serialized_start=6376,
+  serialized_end=6482,
 )
 _sym_db.RegisterEnumDescriptor(_ARTIFACTSBYSERVICE_TEST_ARTIFACTTYPE)
 
@@ -668,8 +638,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=7351,
-  serialized_end=7468,
+  serialized_start=6929,
+  serialized_end=7046,
 )
 _sym_db.RegisterEnumDescriptor(_ARTIFACTSBYSERVICE_FIRMWARE_ARTIFACTTYPE)
 
@@ -690,37 +660,11 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=7841,
-  serialized_end=7904,
+  serialized_start=7349,
+  serialized_end=7412,
 )
 _sym_db.RegisterEnumDescriptor(_ARTIFACTSBYSERVICE_INFRA_ARTIFACTTYPE)
 
-_ARTIFACTSBYSERVICE_PUBLISHCONDITION = _descriptor.EnumDescriptor(
-  name='PublishCondition',
-  full_name='chromiumos.ArtifactsByService.PublishCondition',
-  filename=None,
-  file=DESCRIPTOR,
-  values=[
-    _descriptor.EnumValueDescriptor(
-      name='PUBLISH_UNSPECIFIED', index=0, number=0,
-      serialized_options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='PUBLISH_ON_SUCCESS', index=1, number=1,
-      serialized_options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='PUBLISH_ALWAYS', index=2, number=2,
-      serialized_options=None,
-      type=None),
-  ],
-  containing_type=None,
-  serialized_options=None,
-  serialized_start=7906,
-  serialized_end=7993,
-)
-_sym_db.RegisterEnumDescriptor(_ARTIFACTSBYSERVICE_PUBLISHCONDITION)
-
 
 _BUILDTARGET = _descriptor.Descriptor(
   name='BuildTarget',
@@ -911,6 +855,44 @@
 )
 
 
+_REMOTEEXECCONFIG = _descriptor.Descriptor(
+  name='RemoteexecConfig',
+  full_name='chromiumos.RemoteexecConfig',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='reclient_dir', full_name='chromiumos.RemoteexecConfig.reclient_dir', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='reproxy_cfg_file', full_name='chromiumos.RemoteexecConfig.reproxy_cfg_file', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=348,
+  serialized_end=414,
+)
+
+
 _GOMACONFIG = _descriptor.Descriptor(
   name='GomaConfig',
   full_name='chromiumos.GomaConfig',
@@ -980,8 +962,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=349,
-  serialized_end=684,
+  serialized_start=417,
+  serialized_end=752,
 )
 
 
@@ -1025,8 +1007,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=686,
-  serialized_end=763,
+  serialized_start=754,
+  serialized_end=831,
 )
 
 
@@ -1070,8 +1052,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=765,
-  serialized_end=835,
+  serialized_start=833,
+  serialized_end=903,
 )
 
 
@@ -1101,8 +1083,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=837,
-  serialized_end=860,
+  serialized_start=905,
+  serialized_end=928,
 )
 
 
@@ -1160,8 +1142,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=863,
-  serialized_end=1031,
+  serialized_start=931,
+  serialized_end=1099,
 )
 
 
@@ -1199,8 +1181,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1033,
-  serialized_end=1152,
+  serialized_start=1101,
+  serialized_end=1220,
 )
 
 
@@ -1230,8 +1212,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1154,
-  serialized_end=1198,
+  serialized_start=1222,
+  serialized_end=1266,
 )
 
 
@@ -1261,8 +1243,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1200,
-  serialized_end=1224,
+  serialized_start=1268,
+  serialized_end=1292,
 )
 
 
@@ -1313,8 +1295,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1226,
-  serialized_end=1305,
+  serialized_start=1294,
+  serialized_end=1373,
 )
 
 
@@ -1372,8 +1354,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1307,
-  serialized_end=1396,
+  serialized_start=1375,
+  serialized_end=1464,
 )
 
 
@@ -1403,8 +1385,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1398,
-  serialized_end=1421,
+  serialized_start=1466,
+  serialized_end=1489,
 )
 
 
@@ -1434,8 +1416,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1583,
-  serialized_end=1604,
+  serialized_start=1651,
+  serialized_end=1672,
 )
 
 _RELEASEBUILDER_MILESTONE = _descriptor.Descriptor(
@@ -1478,8 +1460,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1606,
-  serialized_end=1715,
+  serialized_start=1674,
+  serialized_end=1783,
 )
 
 _RELEASEBUILDER = _descriptor.Descriptor(
@@ -1525,8 +1507,8 @@
       name='milestone_message', full_name='chromiumos.ReleaseBuilder.milestone_message',
       index=0, containing_type=None, fields=[]),
   ],
-  serialized_start=1424,
-  serialized_end=1736,
+  serialized_start=1492,
+  serialized_end=1804,
 )
 
 
@@ -1556,8 +1538,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1738,
-  serialized_end=1801,
+  serialized_start=1806,
+  serialized_end=1869,
 )
 
 
@@ -1587,8 +1569,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1899,
-  serialized_end=1951,
+  serialized_start=1967,
+  serialized_end=2019,
 )
 
 _RELEASECHANNELS_RELEASECHANNELSENTRY = _descriptor.Descriptor(
@@ -1624,8 +1606,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1953,
-  serialized_end=2048,
+  serialized_start=2021,
+  serialized_end=2116,
 )
 
 _RELEASECHANNELS = _descriptor.Descriptor(
@@ -1654,8 +1636,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1804,
-  serialized_end=2048,
+  serialized_start=1872,
+  serialized_end=2116,
 )
 
 
@@ -1685,8 +1667,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2050,
-  serialized_end=2088,
+  serialized_start=2118,
+  serialized_end=2156,
 )
 
 
@@ -1726,8 +1708,8 @@
       name='prepare_for_build_args', full_name='chromiumos.PrepareForBuildAdditionalArgs.prepare_for_build_args',
       index=0, containing_type=None, fields=[]),
   ],
-  serialized_start=2090,
-  serialized_end=2203,
+  serialized_start=2158,
+  serialized_end=2271,
 )
 
 
@@ -1764,8 +1746,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2205,
-  serialized_end=2270,
+  serialized_start=2273,
+  serialized_end=2338,
 )
 
 
@@ -1812,8 +1794,8 @@
       name='artifact_profile_info', full_name='chromiumos.ArtifactProfileInfo.artifact_profile_info',
       index=0, containing_type=None, fields=[]),
   ],
-  serialized_start=2273,
-  serialized_end=2424,
+  serialized_start=2341,
+  serialized_end=2492,
 )
 
 
@@ -1844,8 +1826,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2951,
-  serialized_end=3127,
+  serialized_start=3019,
+  serialized_end=3195,
 )
 
 _ARTIFACTSBYSERVICE_LEGACY_ARTIFACTINFO = _descriptor.Descriptor(
@@ -1876,13 +1858,6 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='publish_condition', full_name='chromiumos.ArtifactsByService.Legacy.ArtifactInfo.publish_condition', index=3,
-      number=5, type=14, cpp_type=8, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -1895,8 +1870,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3296,
-  serialized_end=3522,
+  serialized_start=3364,
+  serialized_end=3520,
 )
 
 _ARTIFACTSBYSERVICE_LEGACY = _descriptor.Descriptor(
@@ -1933,8 +1908,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3130,
-  serialized_end=3820,
+  serialized_start=3198,
+  serialized_end=3818,
 )
 
 _ARTIFACTSBYSERVICE_TOOLCHAIN_ARTIFACTINFO = _descriptor.Descriptor(
@@ -1965,13 +1940,6 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='publish_condition', full_name='chromiumos.ArtifactsByService.Toolchain.ArtifactInfo.publish_condition', index=3,
-      number=5, type=14, cpp_type=8, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -1984,8 +1952,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3998,
-  serialized_end=4207,
+  serialized_start=3996,
+  serialized_end=4135,
 )
 
 _ARTIFACTSBYSERVICE_TOOLCHAIN = _descriptor.Descriptor(
@@ -2022,8 +1990,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3823,
-  serialized_end=4846,
+  serialized_start=3821,
+  serialized_end=4774,
 )
 
 _ARTIFACTSBYSERVICE_IMAGE_ARTIFACTINFO = _descriptor.Descriptor(
@@ -2054,13 +2022,6 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='publish_condition', full_name='chromiumos.ArtifactsByService.Image.ArtifactInfo.publish_condition', index=3,
-      number=5, type=14, cpp_type=8, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -2073,8 +2034,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5012,
-  serialized_end=5217,
+  serialized_start=4940,
+  serialized_end=5075,
 )
 
 _ARTIFACTSBYSERVICE_IMAGE = _descriptor.Descriptor(
@@ -2111,8 +2072,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4849,
-  serialized_end=5323,
+  serialized_start=4777,
+  serialized_end=5181,
 )
 
 _ARTIFACTSBYSERVICE_PACKAGE_ARTIFACTINFO = _descriptor.Descriptor(
@@ -2143,13 +2104,6 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='publish_condition', full_name='chromiumos.ArtifactsByService.Package.ArtifactInfo.publish_condition', index=3,
-      number=5, type=14, cpp_type=8, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -2162,8 +2116,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5495,
-  serialized_end=5702,
+  serialized_start=5353,
+  serialized_end=5490,
 )
 
 _ARTIFACTSBYSERVICE_PACKAGE = _descriptor.Descriptor(
@@ -2200,8 +2154,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5326,
-  serialized_end=5741,
+  serialized_start=5184,
+  serialized_end=5529,
 )
 
 _ARTIFACTSBYSERVICE_SYSROOT_ARTIFACTINFO = _descriptor.Descriptor(
@@ -2232,13 +2186,6 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='publish_condition', full_name='chromiumos.ArtifactsByService.Sysroot.ArtifactInfo.publish_condition', index=3,
-      number=5, type=14, cpp_type=8, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -2251,8 +2198,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5913,
-  serialized_end=6120,
+  serialized_start=5701,
+  serialized_end=5838,
 )
 
 _ARTIFACTSBYSERVICE_SYSROOT = _descriptor.Descriptor(
@@ -2289,8 +2236,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5744,
-  serialized_end=6269,
+  serialized_start=5532,
+  serialized_end=5987,
 )
 
 _ARTIFACTSBYSERVICE_TEST_ARTIFACTINFO = _descriptor.Descriptor(
@@ -2322,14 +2269,7 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='publish_condition', full_name='chromiumos.ArtifactsByService.Test.ArtifactInfo.publish_condition', index=3,
-      number=5, type=14, cpp_type=8, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='code_coverage_upload_info', full_name='chromiumos.ArtifactsByService.Test.ArtifactInfo.code_coverage_upload_info', index=4,
+      name='code_coverage_upload_info', full_name='chromiumos.ArtifactsByService.Test.ArtifactInfo.code_coverage_upload_info', index=3,
       number=6, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
@@ -2347,8 +2287,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=6432,
-  serialized_end=6726,
+  serialized_start=6150,
+  serialized_end=6374,
 )
 
 _ARTIFACTSBYSERVICE_TEST = _descriptor.Descriptor(
@@ -2385,8 +2325,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=6272,
-  serialized_end=6834,
+  serialized_start=5990,
+  serialized_end=6482,
 )
 
 _ARTIFACTSBYSERVICE_FIRMWARE_ARTIFACTINFO = _descriptor.Descriptor(
@@ -2418,21 +2358,14 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='publish_condition', full_name='chromiumos.ArtifactsByService.Firmware.ArtifactInfo.publish_condition', index=3,
-      number=5, type=14, cpp_type=8, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='location', full_name='chromiumos.ArtifactsByService.Firmware.ArtifactInfo.location', index=4,
+      name='location', full_name='chromiumos.ArtifactsByService.Firmware.ArtifactInfo.location', index=3,
       number=6, type=14, cpp_type=8, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='code_coverage_upload_info', full_name='chromiumos.ArtifactsByService.Firmware.ArtifactInfo.code_coverage_upload_info', index=5,
+      name='code_coverage_upload_info', full_name='chromiumos.ArtifactsByService.Firmware.ArtifactInfo.code_coverage_upload_info', index=4,
       number=7, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
@@ -2450,8 +2383,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=7009,
-  serialized_end=7349,
+  serialized_start=6657,
+  serialized_end=6927,
 )
 
 _ARTIFACTSBYSERVICE_FIRMWARE = _descriptor.Descriptor(
@@ -2488,8 +2421,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=6837,
-  serialized_end=7468,
+  serialized_start=6485,
+  serialized_end=7046,
 )
 
 _ARTIFACTSBYSERVICE_INFRA_ARTIFACTINFO = _descriptor.Descriptor(
@@ -2520,13 +2453,6 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='publish_condition', full_name='chromiumos.ArtifactsByService.Infra.ArtifactInfo.publish_condition', index=3,
-      number=5, type=14, cpp_type=8, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -2539,8 +2465,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=7634,
-  serialized_end=7839,
+  serialized_start=7212,
+  serialized_end=7347,
 )
 
 _ARTIFACTSBYSERVICE_INFRA = _descriptor.Descriptor(
@@ -2577,8 +2503,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=7471,
-  serialized_end=7904,
+  serialized_start=7049,
+  serialized_end=7412,
 )
 
 _ARTIFACTSBYSERVICE = _descriptor.Descriptor(
@@ -2656,7 +2582,6 @@
   ],
   nested_types=[_ARTIFACTSBYSERVICE_CODECOVERAGEUPLOADINFO, _ARTIFACTSBYSERVICE_LEGACY, _ARTIFACTSBYSERVICE_TOOLCHAIN, _ARTIFACTSBYSERVICE_IMAGE, _ARTIFACTSBYSERVICE_PACKAGE, _ARTIFACTSBYSERVICE_SYSROOT, _ARTIFACTSBYSERVICE_TEST, _ARTIFACTSBYSERVICE_FIRMWARE, _ARTIFACTSBYSERVICE_INFRA, ],
   enum_types=[
-    _ARTIFACTSBYSERVICE_PUBLISHCONDITION,
   ],
   serialized_options=None,
   is_extendable=False,
@@ -2664,8 +2589,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2427,
-  serialized_end=7993,
+  serialized_start=2495,
+  serialized_end=7412,
 )
 
 
@@ -2702,8 +2627,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=8627,
-  serialized_end=8750,
+  serialized_start=8046,
+  serialized_end=8169,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_LEGACY = _descriptor.Descriptor(
@@ -2732,8 +2657,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=8537,
-  serialized_end=8750,
+  serialized_start=7956,
+  serialized_end=8169,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_TOOLCHAIN_ARTIFACTPATHS = _descriptor.Descriptor(
@@ -2769,8 +2694,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=8849,
-  serialized_end=8975,
+  serialized_start=8268,
+  serialized_end=8394,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_TOOLCHAIN = _descriptor.Descriptor(
@@ -2799,8 +2724,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=8753,
-  serialized_end=8975,
+  serialized_start=8172,
+  serialized_end=8394,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_IMAGE_ARTIFACTPATHS = _descriptor.Descriptor(
@@ -2836,8 +2761,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9066,
-  serialized_end=9188,
+  serialized_start=8485,
+  serialized_end=8607,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_IMAGE = _descriptor.Descriptor(
@@ -2866,8 +2791,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=8978,
-  serialized_end=9188,
+  serialized_start=8397,
+  serialized_end=8607,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_PACKAGE_ARTIFACTPATHS = _descriptor.Descriptor(
@@ -2903,8 +2828,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9283,
-  serialized_end=9407,
+  serialized_start=8702,
+  serialized_end=8826,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_PACKAGE = _descriptor.Descriptor(
@@ -2933,8 +2858,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9191,
-  serialized_end=9407,
+  serialized_start=8610,
+  serialized_end=8826,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_SYSROOT_ARTIFACTPATHS = _descriptor.Descriptor(
@@ -2970,8 +2895,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9502,
-  serialized_end=9626,
+  serialized_start=8921,
+  serialized_end=9045,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_SYSROOT = _descriptor.Descriptor(
@@ -3000,8 +2925,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9410,
-  serialized_end=9626,
+  serialized_start=8829,
+  serialized_end=9045,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_TEST_ARTIFACTPATHS = _descriptor.Descriptor(
@@ -3037,8 +2962,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9715,
-  serialized_end=9836,
+  serialized_start=9134,
+  serialized_end=9255,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_TEST = _descriptor.Descriptor(
@@ -3067,8 +2992,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9629,
-  serialized_end=9836,
+  serialized_start=9048,
+  serialized_end=9255,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_FIRMWARE_ARTIFACTPATHS = _descriptor.Descriptor(
@@ -3111,8 +3036,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9934,
-  serialized_end=10101,
+  serialized_start=9353,
+  serialized_end=9520,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_FIRMWARE = _descriptor.Descriptor(
@@ -3141,8 +3066,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9839,
-  serialized_end=10101,
+  serialized_start=9258,
+  serialized_end=9520,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_INFRA_ARTIFACTPATHS = _descriptor.Descriptor(
@@ -3178,8 +3103,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=10192,
-  serialized_end=10314,
+  serialized_start=9611,
+  serialized_end=9733,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE_INFRA = _descriptor.Descriptor(
@@ -3208,8 +3133,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=10104,
-  serialized_end=10314,
+  serialized_start=9523,
+  serialized_end=9733,
 )
 
 _UPLOADEDARTIFACTSBYSERVICE = _descriptor.Descriptor(
@@ -3287,8 +3212,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=7996,
-  serialized_end=10314,
+  serialized_start=7415,
+  serialized_end=9733,
 )
 
 _CHROOT_CHROOTENV.fields_by_name['use_flags'].message_type = _USEFLAG
@@ -3337,42 +3262,36 @@
 _ARTIFACTSBYSERVICE_CODECOVERAGEUPLOADINFO.containing_type = _ARTIFACTSBYSERVICE
 _ARTIFACTSBYSERVICE_CODECOVERAGEUPLOADINFO_CODECOVERAGETYPE.containing_type = _ARTIFACTSBYSERVICE_CODECOVERAGEUPLOADINFO
 _ARTIFACTSBYSERVICE_LEGACY_ARTIFACTINFO.fields_by_name['artifact_types'].enum_type = _ARTIFACTSBYSERVICE_LEGACY_ARTIFACTTYPE
-_ARTIFACTSBYSERVICE_LEGACY_ARTIFACTINFO.fields_by_name['publish_condition'].enum_type = _ARTIFACTSBYSERVICE_PUBLISHCONDITION
 _ARTIFACTSBYSERVICE_LEGACY_ARTIFACTINFO.containing_type = _ARTIFACTSBYSERVICE_LEGACY
 _ARTIFACTSBYSERVICE_LEGACY.fields_by_name['input_artifacts'].message_type = _ARTIFACTSBYSERVICE_LEGACY_ARTIFACTINFO
 _ARTIFACTSBYSERVICE_LEGACY.fields_by_name['output_artifacts'].message_type = _ARTIFACTSBYSERVICE_LEGACY_ARTIFACTINFO
 _ARTIFACTSBYSERVICE_LEGACY.containing_type = _ARTIFACTSBYSERVICE
 _ARTIFACTSBYSERVICE_LEGACY_ARTIFACTTYPE.containing_type = _ARTIFACTSBYSERVICE_LEGACY
 _ARTIFACTSBYSERVICE_TOOLCHAIN_ARTIFACTINFO.fields_by_name['artifact_types'].enum_type = _ARTIFACTSBYSERVICE_TOOLCHAIN_ARTIFACTTYPE
-_ARTIFACTSBYSERVICE_TOOLCHAIN_ARTIFACTINFO.fields_by_name['publish_condition'].enum_type = _ARTIFACTSBYSERVICE_PUBLISHCONDITION
 _ARTIFACTSBYSERVICE_TOOLCHAIN_ARTIFACTINFO.containing_type = _ARTIFACTSBYSERVICE_TOOLCHAIN
 _ARTIFACTSBYSERVICE_TOOLCHAIN.fields_by_name['input_artifacts'].message_type = _ARTIFACTSBYSERVICE_TOOLCHAIN_ARTIFACTINFO
 _ARTIFACTSBYSERVICE_TOOLCHAIN.fields_by_name['output_artifacts'].message_type = _ARTIFACTSBYSERVICE_TOOLCHAIN_ARTIFACTINFO
 _ARTIFACTSBYSERVICE_TOOLCHAIN.containing_type = _ARTIFACTSBYSERVICE
 _ARTIFACTSBYSERVICE_TOOLCHAIN_ARTIFACTTYPE.containing_type = _ARTIFACTSBYSERVICE_TOOLCHAIN
 _ARTIFACTSBYSERVICE_IMAGE_ARTIFACTINFO.fields_by_name['artifact_types'].enum_type = _ARTIFACTSBYSERVICE_IMAGE_ARTIFACTTYPE
-_ARTIFACTSBYSERVICE_IMAGE_ARTIFACTINFO.fields_by_name['publish_condition'].enum_type = _ARTIFACTSBYSERVICE_PUBLISHCONDITION
 _ARTIFACTSBYSERVICE_IMAGE_ARTIFACTINFO.containing_type = _ARTIFACTSBYSERVICE_IMAGE
 _ARTIFACTSBYSERVICE_IMAGE.fields_by_name['input_artifacts'].message_type = _ARTIFACTSBYSERVICE_IMAGE_ARTIFACTINFO
 _ARTIFACTSBYSERVICE_IMAGE.fields_by_name['output_artifacts'].message_type = _ARTIFACTSBYSERVICE_IMAGE_ARTIFACTINFO
 _ARTIFACTSBYSERVICE_IMAGE.containing_type = _ARTIFACTSBYSERVICE
 _ARTIFACTSBYSERVICE_IMAGE_ARTIFACTTYPE.containing_type = _ARTIFACTSBYSERVICE_IMAGE
 _ARTIFACTSBYSERVICE_PACKAGE_ARTIFACTINFO.fields_by_name['artifact_types'].enum_type = _ARTIFACTSBYSERVICE_PACKAGE_ARTIFACTTYPE
-_ARTIFACTSBYSERVICE_PACKAGE_ARTIFACTINFO.fields_by_name['publish_condition'].enum_type = _ARTIFACTSBYSERVICE_PUBLISHCONDITION
 _ARTIFACTSBYSERVICE_PACKAGE_ARTIFACTINFO.containing_type = _ARTIFACTSBYSERVICE_PACKAGE
 _ARTIFACTSBYSERVICE_PACKAGE.fields_by_name['input_artifacts'].message_type = _ARTIFACTSBYSERVICE_PACKAGE_ARTIFACTINFO
 _ARTIFACTSBYSERVICE_PACKAGE.fields_by_name['output_artifacts'].message_type = _ARTIFACTSBYSERVICE_PACKAGE_ARTIFACTINFO
 _ARTIFACTSBYSERVICE_PACKAGE.containing_type = _ARTIFACTSBYSERVICE
 _ARTIFACTSBYSERVICE_PACKAGE_ARTIFACTTYPE.containing_type = _ARTIFACTSBYSERVICE_PACKAGE
 _ARTIFACTSBYSERVICE_SYSROOT_ARTIFACTINFO.fields_by_name['artifact_types'].enum_type = _ARTIFACTSBYSERVICE_SYSROOT_ARTIFACTTYPE
-_ARTIFACTSBYSERVICE_SYSROOT_ARTIFACTINFO.fields_by_name['publish_condition'].enum_type = _ARTIFACTSBYSERVICE_PUBLISHCONDITION
 _ARTIFACTSBYSERVICE_SYSROOT_ARTIFACTINFO.containing_type = _ARTIFACTSBYSERVICE_SYSROOT
 _ARTIFACTSBYSERVICE_SYSROOT.fields_by_name['input_artifacts'].message_type = _ARTIFACTSBYSERVICE_SYSROOT_ARTIFACTINFO
 _ARTIFACTSBYSERVICE_SYSROOT.fields_by_name['output_artifacts'].message_type = _ARTIFACTSBYSERVICE_SYSROOT_ARTIFACTINFO
 _ARTIFACTSBYSERVICE_SYSROOT.containing_type = _ARTIFACTSBYSERVICE
 _ARTIFACTSBYSERVICE_SYSROOT_ARTIFACTTYPE.containing_type = _ARTIFACTSBYSERVICE_SYSROOT
 _ARTIFACTSBYSERVICE_TEST_ARTIFACTINFO.fields_by_name['artifact_types'].enum_type = _ARTIFACTSBYSERVICE_TEST_ARTIFACTTYPE
-_ARTIFACTSBYSERVICE_TEST_ARTIFACTINFO.fields_by_name['publish_condition'].enum_type = _ARTIFACTSBYSERVICE_PUBLISHCONDITION
 _ARTIFACTSBYSERVICE_TEST_ARTIFACTINFO.fields_by_name['code_coverage_upload_info'].message_type = _ARTIFACTSBYSERVICE_CODECOVERAGEUPLOADINFO
 _ARTIFACTSBYSERVICE_TEST_ARTIFACTINFO.containing_type = _ARTIFACTSBYSERVICE_TEST
 _ARTIFACTSBYSERVICE_TEST.fields_by_name['input_artifacts'].message_type = _ARTIFACTSBYSERVICE_TEST_ARTIFACTINFO
@@ -3380,7 +3299,6 @@
 _ARTIFACTSBYSERVICE_TEST.containing_type = _ARTIFACTSBYSERVICE
 _ARTIFACTSBYSERVICE_TEST_ARTIFACTTYPE.containing_type = _ARTIFACTSBYSERVICE_TEST
 _ARTIFACTSBYSERVICE_FIRMWARE_ARTIFACTINFO.fields_by_name['artifact_types'].enum_type = _ARTIFACTSBYSERVICE_FIRMWARE_ARTIFACTTYPE
-_ARTIFACTSBYSERVICE_FIRMWARE_ARTIFACTINFO.fields_by_name['publish_condition'].enum_type = _ARTIFACTSBYSERVICE_PUBLISHCONDITION
 _ARTIFACTSBYSERVICE_FIRMWARE_ARTIFACTINFO.fields_by_name['location'].enum_type = _FWLOCATION
 _ARTIFACTSBYSERVICE_FIRMWARE_ARTIFACTINFO.fields_by_name['code_coverage_upload_info'].message_type = _ARTIFACTSBYSERVICE_CODECOVERAGEUPLOADINFO
 _ARTIFACTSBYSERVICE_FIRMWARE_ARTIFACTINFO.containing_type = _ARTIFACTSBYSERVICE_FIRMWARE
@@ -3389,7 +3307,6 @@
 _ARTIFACTSBYSERVICE_FIRMWARE.containing_type = _ARTIFACTSBYSERVICE
 _ARTIFACTSBYSERVICE_FIRMWARE_ARTIFACTTYPE.containing_type = _ARTIFACTSBYSERVICE_FIRMWARE
 _ARTIFACTSBYSERVICE_INFRA_ARTIFACTINFO.fields_by_name['artifact_types'].enum_type = _ARTIFACTSBYSERVICE_INFRA_ARTIFACTTYPE
-_ARTIFACTSBYSERVICE_INFRA_ARTIFACTINFO.fields_by_name['publish_condition'].enum_type = _ARTIFACTSBYSERVICE_PUBLISHCONDITION
 _ARTIFACTSBYSERVICE_INFRA_ARTIFACTINFO.containing_type = _ARTIFACTSBYSERVICE_INFRA
 _ARTIFACTSBYSERVICE_INFRA.fields_by_name['input_artifacts'].message_type = _ARTIFACTSBYSERVICE_INFRA_ARTIFACTINFO
 _ARTIFACTSBYSERVICE_INFRA.fields_by_name['output_artifacts'].message_type = _ARTIFACTSBYSERVICE_INFRA_ARTIFACTINFO
@@ -3404,7 +3321,6 @@
 _ARTIFACTSBYSERVICE.fields_by_name['profile_info'].message_type = _ARTIFACTPROFILEINFO
 _ARTIFACTSBYSERVICE.fields_by_name['firmware'].message_type = _ARTIFACTSBYSERVICE_FIRMWARE
 _ARTIFACTSBYSERVICE.fields_by_name['infra'].message_type = _ARTIFACTSBYSERVICE_INFRA
-_ARTIFACTSBYSERVICE_PUBLISHCONDITION.containing_type = _ARTIFACTSBYSERVICE
 _UPLOADEDARTIFACTSBYSERVICE_LEGACY_ARTIFACTPATHS.fields_by_name['artifact_type'].enum_type = _ARTIFACTSBYSERVICE_LEGACY_ARTIFACTTYPE
 _UPLOADEDARTIFACTSBYSERVICE_LEGACY_ARTIFACTPATHS.fields_by_name['paths'].message_type = _PATH
 _UPLOADEDARTIFACTSBYSERVICE_LEGACY_ARTIFACTPATHS.containing_type = _UPLOADEDARTIFACTSBYSERVICE_LEGACY
@@ -3458,6 +3374,7 @@
 DESCRIPTOR.message_types_by_name['GcsPath'] = _GCSPATH
 DESCRIPTOR.message_types_by_name['Chroot'] = _CHROOT
 DESCRIPTOR.message_types_by_name['Feature'] = _FEATURE
+DESCRIPTOR.message_types_by_name['RemoteexecConfig'] = _REMOTEEXECCONFIG
 DESCRIPTOR.message_types_by_name['GomaConfig'] = _GOMACONFIG
 DESCRIPTOR.message_types_by_name['GomaArtifacts'] = _GOMAARTIFACTS
 DESCRIPTOR.message_types_by_name['PackageInfo'] = _PACKAGEINFO
@@ -3482,7 +3399,6 @@
 DESCRIPTOR.enum_types_by_name['Channel'] = _CHANNEL
 DESCRIPTOR.enum_types_by_name['DeltaType'] = _DELTATYPE
 DESCRIPTOR.enum_types_by_name['FwLocation'] = _FWLOCATION
-DESCRIPTOR.enum_types_by_name['AFDOArtifactType'] = _AFDOARTIFACTTYPE
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
 BuildTarget = _reflection.GeneratedProtocolMessageType('BuildTarget', (_message.Message,), {
@@ -3521,6 +3437,13 @@
   })
 _sym_db.RegisterMessage(Feature)
 
+RemoteexecConfig = _reflection.GeneratedProtocolMessageType('RemoteexecConfig', (_message.Message,), {
+  'DESCRIPTOR' : _REMOTEEXECCONFIG,
+  '__module__' : 'chromiumos.common_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.RemoteexecConfig)
+  })
+_sym_db.RegisterMessage(RemoteexecConfig)
+
 GomaConfig = _reflection.GeneratedProtocolMessageType('GomaConfig', (_message.Message,), {
   'DESCRIPTOR' : _GOMACONFIG,
   '__module__' : 'chromiumos.common_pb2'
diff --git a/api/gen_sdk/chromiumos/config/api/component_pb2.py b/api/gen_sdk/chromiumos/config/api/component_pb2.py
index 7d4af7a..862787f 100644
--- a/api/gen_sdk/chromiumos/config/api/component_pb2.py
+++ b/api/gen_sdk/chromiumos/config/api/component_pb2.py
@@ -13,6 +13,7 @@
 
 from chromite.api.gen_sdk.chromiumos.config.api import component_id_pb2 as chromiumos_dot_config_dot_api_dot_component__id__pb2
 from chromite.api.gen_sdk.chromiumos.config.api import partner_id_pb2 as chromiumos_dot_config_dot_api_dot_partner__id__pb2
+from google.protobuf import wrappers_pb2 as google_dot_protobuf_dot_wrappers__pb2
 
 
 DESCRIPTOR = _descriptor.FileDescriptor(
@@ -20,9 +21,9 @@
   package='chromiumos.config.api',
   syntax='proto3',
   serialized_options=b'Z(go.chromium.org/chromiumos/config/go/api',
-  serialized_pb=b'\n%chromiumos/config/api/component.proto\x12\x15\x63hromiumos.config.api\x1a(chromiumos/config/api/component_id.proto\x1a&chromiumos/config/api/partner_id.proto\"\x8d(\n\tComponent\x12.\n\x02id\x18\x01 \x01(\x0b\x32\".chromiumos.config.api.ComponentId\x12\x39\n\x0fmanufacturer_id\x18\x08 \x01(\x0b\x32 .chromiumos.config.api.PartnerId\x12\x0c\n\x04name\x18\t \x01(\t\x12\x11\n\thwid_type\x18\x19 \x01(\t\x12\x12\n\nhwid_label\x18\x14 \x01(\t\x12\x36\n\x06\x61vl_id\x18\x15 \x01(\x0b\x32&.chromiumos.config.api.Component.AVLId\x12\x13\n\x0bpart_number\x18\x16 \x01(\t\x12\x33\n\x03soc\x18\x02 \x01(\x0b\x32$.chromiumos.config.api.Component.SocH\x00\x12\x39\n\x06memory\x18\x03 \x01(\x0b\x32\'.chromiumos.config.api.Component.MemoryH\x00\x12?\n\tbluetooth\x18\x04 \x01(\x0b\x32*.chromiumos.config.api.Component.BluetoothH\x00\x12\x39\n\x06\x63\x61mera\x18\x05 \x01(\x0b\x32\'.chromiumos.config.api.Component.CameraH\x00\x12=\n\x0btouchscreen\x18\x06 \x01(\x0b\x32&.chromiumos.config.api.Component.TouchH\x00\x12\x35\n\x04wifi\x18\x07 \x01(\x0b\x32%.chromiumos.config.api.Component.WifiH\x00\x12:\n\x08touchpad\x18\n \x01(\x0b\x32&.chromiumos.config.api.Component.TouchH\x00\x12\x46\n\rdisplay_panel\x18\x0b \x01(\x0b\x32-.chromiumos.config.api.Component.DisplayPanelH\x00\x12\x42\n\x0b\x61udio_codec\x18\x0c \x01(\x0b\x32+.chromiumos.config.api.Component.AudioCodecH\x00\x12;\n\x07\x62\x61ttery\x18\r \x01(\x0b\x32(.chromiumos.config.api.Component.BatteryH\x00\x12\x43\n\rec_flash_chip\x18\x0e \x01(\x0b\x32*.chromiumos.config.api.Component.FlashChipH\x00\x12G\n\x11system_flash_chip\x18\x0f \x01(\x0b\x32*.chromiumos.config.api.Component.FlashChipH\x00\x12\x41\n\x02\x65\x63\x18\x10 \x01(\x0b\x32\x33.chromiumos.config.api.Component.EmbeddedControllerH\x00\x12;\n\x07storage\x18\x11 \x01(\x0b\x32(.chromiumos.config.api.Component.StorageH\x00\x12\x33\n\x03tpm\x18\x12 \x01(\x0b\x32$.chromiumos.config.api.Component.TpmH\x00\x12\x42\n\x08usb_host\x18\x13 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.UsbH\x00\x12\x39\n\x06stylus\x18\x17 \x01(\x0b\x32\'.chromiumos.config.api.Component.StylusH\x00\x12?\n\tamplifier\x18\x18 \x01(\x0b\x32*.chromiumos.config.api.Component.AmplifierH\x00\x12M\n\x0c\x64p_converter\x18\x1a \x01(\x0b\x32\x35.chromiumos.config.api.Component.DisplayPortConverterH\x00\x12=\n\x08\x63\x65llular\x18\x1b \x01(\x0b\x32).chromiumos.config.api.Component.CellularH\x00\x1a!\n\x05\x41VLId\x12\x0b\n\x03\x63id\x18\x01 \x01(\x05\x12\x0b\n\x03qid\x18\x02 \x01(\x05\x1a\xb7\x01\n\tInterface\x1a&\n\x03I2C\x12\x0f\n\x07product\x18\x01 \x01(\t\x12\x0e\n\x06vendor\x18\x02 \x01(\t\x1a@\n\x03Usb\x12\x11\n\tvendor_id\x18\x01 \x01(\t\x12\x12\n\nproduct_id\x18\x02 \x01(\t\x12\x12\n\nbcd_device\x18\x03 \x01(\t\x1a@\n\x03Pci\x12\x11\n\tvendor_id\x18\x01 \x01(\t\x12\x11\n\tdevice_id\x18\x02 \x01(\t\x12\x13\n\x0brevision_id\x18\x03 \x01(\t\x1a\xf7\x02\n\x03Soc\x12;\n\x06\x66\x61mily\x18\x01 \x01(\x0b\x32+.chromiumos.config.api.Component.Soc.Family\x12\r\n\x05model\x18\x02 \x01(\t\x12\r\n\x05\x63ores\x18\x03 \x01(\x05\x12>\n\x08\x66\x65\x61tures\x18\x04 \x03(\x0e\x32,.chromiumos.config.api.Component.Soc.Feature\x1aW\n\x06\x46\x61mily\x12?\n\x04\x61rch\x18\x01 \x01(\x0e\x32\x31.chromiumos.config.api.Component.Soc.Architecture\x12\x0c\n\x04name\x18\x02 \x01(\t\"S\n\x0c\x41rchitecture\x12\x1a\n\x16\x41RCHITECTURE_UNDEFINED\x10\x00\x12\x07\n\x03X86\x10\x01\x12\n\n\x06X86_64\x10\x02\x12\x07\n\x03\x41RM\x10\x03\x12\t\n\x05\x41RM64\x10\x04\"\'\n\x07\x46\x65\x61ture\x12\x13\n\x0f\x46\x45\x41TURE_UNKNOWN\x10\x00\x12\x07\n\x03SMT\x10\x01\x1a\xb4\x02\n\x06Memory\x12@\n\x07profile\x18\x01 \x01(\x0b\x32/.chromiumos.config.api.Component.Memory.Profile\x12\x13\n\x0bpart_number\x18\x02 \x01(\t\x1ap\n\x07Profile\x12:\n\x04type\x18\x01 \x01(\x0e\x32,.chromiumos.config.api.Component.Memory.Type\x12\x11\n\tspeed_mhz\x18\x02 \x01(\x05\x12\x16\n\x0esize_megabytes\x18\x03 \x01(\x05\"[\n\x04Type\x12\x12\n\x0eTYPE_UNDEFINED\x10\x00\x12\x07\n\x03\x44\x44R\x10\x01\x12\x08\n\x04\x44\x44R2\x10\x02\x12\x08\n\x04\x44\x44R3\x10\x03\x12\x08\n\x04\x44\x44R4\x10\x04\x12\x0b\n\x07LP_DDR3\x10\x05\x12\x0b\n\x07LP_DDR4\x10\x06J\x04\x08\x03\x10\x04\x1aZ\n\tBluetooth\x12;\n\x03usb\x18\x04 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.UsbJ\x04\x08\x01\x10\x02J\x04\x08\x02\x10\x03J\x04\x08\x03\x10\x04\x1a\x93\x03\n\x06\x43\x61mera\x12\x41\n\x08\x66\x65\x61tures\x18\x01 \x03(\x0e\x32/.chromiumos.config.api.Component.Camera.Feature\x12\x45\n\nclock_type\x18\x02 \x01(\x0e\x32\x31.chromiumos.config.api.Component.Camera.ClockType\x12=\n\x03usb\x18\x03 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.UsbH\x00\x12=\n\x03pci\x18\x04 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.PciH\x00\"0\n\x07\x46\x65\x61ture\x12\x13\n\x0f\x46\x45\x41TURE_UNKNOWN\x10\x00\x12\x10\n\x0c\x41\x43TIVITY_LED\x10\x01\"B\n\tClockType\x12\x18\n\x14\x43LOCK_TYPE_UNDEFINED\x10\x00\x12\r\n\tMONOTONIC\x10\x01\x12\x0c\n\x08\x42OOTTIME\x10\x02\x42\x0b\n\tinterface\x1a\xc9\x02\n\x0c\x44isplayPanel\x12\x12\n\nproduct_id\x18\x01 \x01(\t\x12L\n\nproperties\x18\x02 \x01(\x0b\x32\x38.chromiumos.config.api.Component.DisplayPanel.Properties\x1a\xad\x01\n\nProperties\x12\x10\n\x08width_px\x18\x01 \x01(\x05\x12\x11\n\theight_px\x18\x02 \x01(\x05\x12\x1a\n\x12\x64iagonal_milliinch\x18\x03 \x01(\x05\x12\x15\n\rpixels_per_in\x18\x04 \x01(\x05\x12G\n\x08\x66\x65\x61tures\x18\x05 \x03(\x0e\x32\x35.chromiumos.config.api.Component.DisplayPanel.Feature\"\'\n\x07\x46\x65\x61ture\x12\x13\n\x0f\x46\x45\x41TURE_UNKNOWN\x10\x00\x12\x07\n\x03HDR\x10\x01\x1a\x9e\x02\n\x05Touch\x12\x12\n\nproduct_id\x18\x02 \x01(\t\x12\x12\n\nfw_version\x18\x03 \x01(\t\x12\x16\n\x0eproduct_series\x18\x05 \x01(\t\x12\x13\n\x0b\x66w_checksum\x18\x06 \x01(\t\x12>\n\x04type\x18\x07 \x01(\x0e\x32\x30.chromiumos.config.api.Component.Touch.TouchType\x12;\n\x03usb\x18\x08 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.Usb\"7\n\tTouchType\x12\x18\n\x14TOUCH_TYPE_UNDEFINED\x10\x00\x12\x07\n\x03USB\x10\x01\x12\x07\n\x03I2C\x10\x02J\x04\x08\x01\x10\x02J\x04\x08\x04\x10\x05\x1a\xc8\x02\n\x04Wifi\x12=\n\x03pci\x18\x01 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.PciH\x00\x12T\n\x18supported_wlan_protocols\x18\x02 \x03(\x0e\x32\x32.chromiumos.config.api.Component.Wifi.WLANProtocol\"\x9d\x01\n\x0cWLANProtocol\x12\x19\n\x15WLAN_PROTOCOL_UNKNOWN\x10\x00\x12\x11\n\rIEEE_802_11_A\x10\x01\x12\x11\n\rIEEE_802_11_B\x10\x02\x12\x11\n\rIEEE_802_11_G\x10\x03\x12\x11\n\rIEEE_802_11_N\x10\x04\x12\x12\n\x0eIEEE_802_11_AC\x10\x05\x12\x12\n\x0eIEEE_802_11_AX\x10\x06\x42\x0b\n\tinterface\x1a\xe7\x01\n\rQualification\x12\x38\n\x0c\x63omponent_id\x18\x01 \x01(\x0b\x32\".chromiumos.config.api.ComponentId\x12\x45\n\x06status\x18\x02 \x01(\x0e\x32\x35.chromiumos.config.api.Component.Qualification.Status\"U\n\x06Status\x12\x12\n\x0eSTATUS_UNKNOWN\x10\x00\x12\r\n\tREQUESTED\x10\x01\x12\x19\n\x15TECHNICALLY_QUALIFIED\x10\x02\x12\r\n\tQUALIFIED\x10\x03\x1a\x9a\x01\n\tAmplifier\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x44\n\x08\x66\x65\x61tures\x18\x02 \x03(\x0e\x32\x32.chromiumos.config.api.Component.Amplifier.Feature\"9\n\x07\x46\x65\x61ture\x12\x13\n\x0f\x46\x45\x41TURE_UNKNOWN\x10\x00\x12\x19\n\x15\x42OOT_TIME_CALIBRATION\x10\x01\x1a\x1a\n\nAudioCodec\x12\x0c\n\x04name\x18\x01 \x01(\t\x1a\x9a\x01\n\x07\x42\x61ttery\x12\r\n\x05model\x18\x01 \x01(\t\x12G\n\ntechnology\x18\x02 \x01(\x0e\x32\x33.chromiumos.config.api.Component.Battery.Technology\"7\n\nTechnology\x12\x10\n\x0cTECH_UNKNOWN\x10\x00\x12\n\n\x06LI_ION\x10\x01\x12\x0b\n\x07LI_POLY\x10\x02\x1a \n\tFlashChip\x12\x13\n\x0bpart_number\x18\x01 \x01(\t\x1a)\n\x12\x45mbeddedController\x12\x13\n\x0bpart_number\x18\x01 \x01(\t\x1a\x86\x02\n\x07Storage\x12\x14\n\x0c\x65mmc5_fw_ver\x18\x01 \x01(\t\x12\x0e\n\x06manfid\x18\x02 \x01(\t\x12\x0c\n\x04name\x18\x03 \x01(\t\x12\r\n\x05oemid\x18\x04 \x01(\t\x12\x0b\n\x03prv\x18\x05 \x01(\t\x12\x0f\n\x07sectors\x18\x06 \x01(\t\x12\x42\n\x04type\x18\x07 \x01(\x0e\x32\x34.chromiumos.config.api.Component.Storage.StorageType\x12\x0f\n\x07size_gb\x18\x08 \x01(\r\"E\n\x0bStorageType\x12\x18\n\x14STORAGE_TYPE_UNKNOWN\x10\x00\x12\x08\n\x04\x45MMC\x10\x01\x12\x08\n\x04NVME\x10\x02\x12\x08\n\x04SATA\x10\x03\x1a\x31\n\x03Tpm\x12\x19\n\x11manufacturer_info\x18\x01 \x01(\t\x12\x0f\n\x07version\x18\x02 \x01(\t\x1a\x93\x01\n\x06Stylus\x12=\n\x03usb\x18\x01 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.UsbH\x00\x12=\n\x03i2c\x18\x02 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.I2CH\x00\x42\x0b\n\tinterface\x1a$\n\x14\x44isplayPortConverter\x12\x0c\n\x04name\x18\x01 \x01(\t\x1aV\n\x08\x43\x65llular\x12=\n\x03usb\x18\x01 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.UsbH\x00\x42\x0b\n\tinterfaceB\x06\n\x04typeB*Z(go.chromium.org/chromiumos/config/go/apib\x06proto3'
+  serialized_pb=b'\n%chromiumos/config/api/component.proto\x12\x15\x63hromiumos.config.api\x1a(chromiumos/config/api/component_id.proto\x1a&chromiumos/config/api/partner_id.proto\x1a\x1egoogle/protobuf/wrappers.proto\"\xb4-\n\tComponent\x12.\n\x02id\x18\x01 \x01(\x0b\x32\".chromiumos.config.api.ComponentId\x12\x39\n\x0fmanufacturer_id\x18\x08 \x01(\x0b\x32 .chromiumos.config.api.PartnerId\x12\x0c\n\x04name\x18\t \x01(\t\x12\x11\n\thwid_type\x18\x19 \x01(\t\x12\x12\n\nhwid_label\x18\x14 \x01(\t\x12\x36\n\x06\x61vl_id\x18\x15 \x01(\x0b\x32&.chromiumos.config.api.Component.AVLId\x12\x13\n\x0bpart_number\x18\x16 \x01(\t\x12\x46\n\x0esupport_status\x18\x1c \x01(\x0e\x32..chromiumos.config.api.Component.SupportStatus\x12\x33\n\x03soc\x18\x02 \x01(\x0b\x32$.chromiumos.config.api.Component.SocH\x00\x12\x39\n\x06memory\x18\x03 \x01(\x0b\x32\'.chromiumos.config.api.Component.MemoryH\x00\x12?\n\tbluetooth\x18\x04 \x01(\x0b\x32*.chromiumos.config.api.Component.BluetoothH\x00\x12\x39\n\x06\x63\x61mera\x18\x05 \x01(\x0b\x32\'.chromiumos.config.api.Component.CameraH\x00\x12=\n\x0btouchscreen\x18\x06 \x01(\x0b\x32&.chromiumos.config.api.Component.TouchH\x00\x12\x35\n\x04wifi\x18\x07 \x01(\x0b\x32%.chromiumos.config.api.Component.WifiH\x00\x12:\n\x08touchpad\x18\n \x01(\x0b\x32&.chromiumos.config.api.Component.TouchH\x00\x12\x46\n\rdisplay_panel\x18\x0b \x01(\x0b\x32-.chromiumos.config.api.Component.DisplayPanelH\x00\x12\x42\n\x0b\x61udio_codec\x18\x0c \x01(\x0b\x32+.chromiumos.config.api.Component.AudioCodecH\x00\x12;\n\x07\x62\x61ttery\x18\r \x01(\x0b\x32(.chromiumos.config.api.Component.BatteryH\x00\x12\x43\n\rec_flash_chip\x18\x0e \x01(\x0b\x32*.chromiumos.config.api.Component.FlashChipH\x00\x12G\n\x11system_flash_chip\x18\x0f \x01(\x0b\x32*.chromiumos.config.api.Component.FlashChipH\x00\x12\x41\n\x02\x65\x63\x18\x10 \x01(\x0b\x32\x33.chromiumos.config.api.Component.EmbeddedControllerH\x00\x12;\n\x07storage\x18\x11 \x01(\x0b\x32(.chromiumos.config.api.Component.StorageH\x00\x12\x33\n\x03tpm\x18\x12 \x01(\x0b\x32$.chromiumos.config.api.Component.TpmH\x00\x12\x42\n\x08usb_host\x18\x13 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.UsbH\x00\x12\x39\n\x06stylus\x18\x17 \x01(\x0b\x32\'.chromiumos.config.api.Component.StylusH\x00\x12?\n\tamplifier\x18\x18 \x01(\x0b\x32*.chromiumos.config.api.Component.AmplifierH\x00\x12M\n\x0c\x64p_converter\x18\x1a \x01(\x0b\x32\x35.chromiumos.config.api.Component.DisplayPortConverterH\x00\x12=\n\x08\x63\x65llular\x18\x1b \x01(\x0b\x32).chromiumos.config.api.Component.CellularH\x00\x1a!\n\x05\x41VLId\x12\x0b\n\x03\x63id\x18\x01 \x01(\x05\x12\x0b\n\x03qid\x18\x02 \x01(\x05\x1a\xc9\x01\n\tInterface\x1a&\n\x03I2C\x12\x0f\n\x07product\x18\x01 \x01(\t\x12\x0e\n\x06vendor\x18\x02 \x01(\t\x1a@\n\x03Usb\x12\x11\n\tvendor_id\x18\x01 \x01(\t\x12\x12\n\nproduct_id\x18\x02 \x01(\t\x12\x12\n\nbcd_device\x18\x03 \x01(\t\x1aR\n\x03Pci\x12\x11\n\tvendor_id\x18\x01 \x01(\t\x12\x11\n\tdevice_id\x18\x02 \x01(\t\x12\x13\n\x0brevision_id\x18\x03 \x01(\t\x12\x10\n\x08\x63lass_id\x18\x04 \x01(\t\x1a\x83\x03\n\x03Soc\x12;\n\x06\x66\x61mily\x18\x01 \x01(\x0b\x32+.chromiumos.config.api.Component.Soc.Family\x12\r\n\x05model\x18\x02 \x01(\t\x12\r\n\x05\x63ores\x18\x03 \x01(\x05\x12>\n\x08\x66\x65\x61tures\x18\x04 \x03(\x0e\x32,.chromiumos.config.api.Component.Soc.Feature\x1aW\n\x06\x46\x61mily\x12?\n\x04\x61rch\x18\x01 \x01(\x0e\x32\x31.chromiumos.config.api.Component.Soc.Architecture\x12\x0c\n\x04name\x18\x02 \x01(\t\"S\n\x0c\x41rchitecture\x12\x1a\n\x16\x41RCHITECTURE_UNDEFINED\x10\x00\x12\x07\n\x03X86\x10\x01\x12\n\n\x06X86_64\x10\x02\x12\x07\n\x03\x41RM\x10\x03\x12\t\n\x05\x41RM64\x10\x04\"3\n\x07\x46\x65\x61ture\x12\x13\n\x0f\x46\x45\x41TURE_UNKNOWN\x10\x00\x12\x07\n\x03SMT\x10\x01\x12\n\n\x06SHA_NI\x10\x02\x1a\xb4\x02\n\x06Memory\x12@\n\x07profile\x18\x01 \x01(\x0b\x32/.chromiumos.config.api.Component.Memory.Profile\x12\x13\n\x0bpart_number\x18\x02 \x01(\t\x1ap\n\x07Profile\x12:\n\x04type\x18\x01 \x01(\x0e\x32,.chromiumos.config.api.Component.Memory.Type\x12\x11\n\tspeed_mhz\x18\x02 \x01(\x05\x12\x16\n\x0esize_megabytes\x18\x03 \x01(\x05\"[\n\x04Type\x12\x12\n\x0eTYPE_UNDEFINED\x10\x00\x12\x07\n\x03\x44\x44R\x10\x01\x12\x08\n\x04\x44\x44R2\x10\x02\x12\x08\n\x04\x44\x44R3\x10\x03\x12\x08\n\x04\x44\x44R4\x10\x04\x12\x0b\n\x07LP_DDR3\x10\x05\x12\x0b\n\x07LP_DDR4\x10\x06J\x04\x08\x03\x10\x04\x1aZ\n\tBluetooth\x12;\n\x03usb\x18\x04 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.UsbJ\x04\x08\x01\x10\x02J\x04\x08\x02\x10\x03J\x04\x08\x03\x10\x04\x1a\x93\x03\n\x06\x43\x61mera\x12\x41\n\x08\x66\x65\x61tures\x18\x01 \x03(\x0e\x32/.chromiumos.config.api.Component.Camera.Feature\x12\x45\n\nclock_type\x18\x02 \x01(\x0e\x32\x31.chromiumos.config.api.Component.Camera.ClockType\x12=\n\x03usb\x18\x03 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.UsbH\x00\x12=\n\x03pci\x18\x04 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.PciH\x00\"0\n\x07\x46\x65\x61ture\x12\x13\n\x0f\x46\x45\x41TURE_UNKNOWN\x10\x00\x12\x10\n\x0c\x41\x43TIVITY_LED\x10\x01\"B\n\tClockType\x12\x18\n\x14\x43LOCK_TYPE_UNDEFINED\x10\x00\x12\r\n\tMONOTONIC\x10\x01\x12\x0c\n\x08\x42OOTTIME\x10\x02\x42\x0b\n\tinterface\x1a\xae\x04\n\x0c\x44isplayPanel\x12\x12\n\nproduct_id\x18\x01 \x01(\t\x12L\n\nproperties\x18\x02 \x01(\x0b\x32\x38.chromiumos.config.api.Component.DisplayPanel.Properties\x1a\x92\x03\n\nProperties\x12\x10\n\x08width_px\x18\x01 \x01(\x05\x12\x11\n\theight_px\x18\x02 \x01(\x05\x12\x1a\n\x12\x64iagonal_milliinch\x18\x03 \x01(\x05\x12\x15\n\rpixels_per_in\x18\x04 \x01(\x05\x12G\n\x08\x66\x65\x61tures\x18\x05 \x03(\x0e\x32\x35.chromiumos.config.api.Component.DisplayPanel.Feature\x12#\n\x1bmin_visible_backlight_level\x18\x06 \x01(\r\x12@\n\x1aturn_off_screen_timeout_ms\x18\x07 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12!\n\x19no_als_battery_brightness\x18\x08 \x01(\x01\x12\x1c\n\x14no_als_ac_brightness\x18\t \x01(\x01\x12;\n\tals_steps\x18\n \x03(\x0b\x32(.chromiumos.config.api.Component.AlsStep\"\'\n\x07\x46\x65\x61ture\x12\x13\n\x0f\x46\x45\x41TURE_UNKNOWN\x10\x00\x12\x07\n\x03HDR\x10\x01\x1a\x9e\x02\n\x05Touch\x12\x12\n\nproduct_id\x18\x02 \x01(\t\x12\x12\n\nfw_version\x18\x03 \x01(\t\x12\x16\n\x0eproduct_series\x18\x05 \x01(\t\x12\x13\n\x0b\x66w_checksum\x18\x06 \x01(\t\x12>\n\x04type\x18\x07 \x01(\x0e\x32\x30.chromiumos.config.api.Component.Touch.TouchType\x12;\n\x03usb\x18\x08 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.Usb\"7\n\tTouchType\x12\x18\n\x14TOUCH_TYPE_UNDEFINED\x10\x00\x12\x07\n\x03USB\x10\x01\x12\x07\n\x03I2C\x10\x02J\x04\x08\x01\x10\x02J\x04\x08\x04\x10\x05\x1a\xc8\x02\n\x04Wifi\x12=\n\x03pci\x18\x01 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.PciH\x00\x12T\n\x18supported_wlan_protocols\x18\x02 \x03(\x0e\x32\x32.chromiumos.config.api.Component.Wifi.WLANProtocol\"\x9d\x01\n\x0cWLANProtocol\x12\x19\n\x15WLAN_PROTOCOL_UNKNOWN\x10\x00\x12\x11\n\rIEEE_802_11_A\x10\x01\x12\x11\n\rIEEE_802_11_B\x10\x02\x12\x11\n\rIEEE_802_11_G\x10\x03\x12\x11\n\rIEEE_802_11_N\x10\x04\x12\x12\n\x0eIEEE_802_11_AC\x10\x05\x12\x12\n\x0eIEEE_802_11_AX\x10\x06\x42\x0b\n\tinterface\x1a\xe7\x01\n\rQualification\x12\x38\n\x0c\x63omponent_id\x18\x01 \x01(\x0b\x32\".chromiumos.config.api.ComponentId\x12\x45\n\x06status\x18\x02 \x01(\x0e\x32\x35.chromiumos.config.api.Component.Qualification.Status\"U\n\x06Status\x12\x12\n\x0eSTATUS_UNKNOWN\x10\x00\x12\r\n\tREQUESTED\x10\x01\x12\x19\n\x15TECHNICALLY_QUALIFIED\x10\x02\x12\r\n\tQUALIFIED\x10\x03\x1a\x9a\x01\n\tAmplifier\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x44\n\x08\x66\x65\x61tures\x18\x02 \x03(\x0e\x32\x32.chromiumos.config.api.Component.Amplifier.Feature\"9\n\x07\x46\x65\x61ture\x12\x13\n\x0f\x46\x45\x41TURE_UNKNOWN\x10\x00\x12\x19\n\x15\x42OOT_TIME_CALIBRATION\x10\x01\x1a\x1a\n\nAudioCodec\x12\x0c\n\x04name\x18\x01 \x01(\t\x1a\x9a\x01\n\x07\x42\x61ttery\x12\r\n\x05model\x18\x01 \x01(\t\x12G\n\ntechnology\x18\x02 \x01(\x0e\x32\x33.chromiumos.config.api.Component.Battery.Technology\"7\n\nTechnology\x12\x10\n\x0cTECH_UNKNOWN\x10\x00\x12\n\n\x06LI_ION\x10\x01\x12\x0b\n\x07LI_POLY\x10\x02\x1a \n\tFlashChip\x12\x13\n\x0bpart_number\x18\x01 \x01(\t\x1a)\n\x12\x45mbeddedController\x12\x13\n\x0bpart_number\x18\x01 \x01(\t\x1a\xd2\x02\n\x07Storage\x12\x14\n\x0c\x65mmc5_fw_ver\x18\x01 \x01(\t\x12\x0e\n\x06manfid\x18\x02 \x01(\t\x12\x0c\n\x04name\x18\x03 \x01(\t\x12\r\n\x05oemid\x18\x04 \x01(\t\x12\x0b\n\x03prv\x18\x05 \x01(\t\x12\x0f\n\x07sectors\x18\x06 \x01(\t\x12\x42\n\x04type\x18\x07 \x01(\x0e\x32\x34.chromiumos.config.api.Component.Storage.StorageType\x12\x0f\n\x07size_gb\x18\x08 \x01(\r\x12=\n\x03pci\x18\t \x01(\x0b\x32..chromiumos.config.api.Component.Interface.PciH\x00\"E\n\x0bStorageType\x12\x18\n\x14STORAGE_TYPE_UNKNOWN\x10\x00\x12\x08\n\x04\x45MMC\x10\x01\x12\x08\n\x04NVME\x10\x02\x12\x08\n\x04SATA\x10\x03\x42\x0b\n\tinterface\x1a\x31\n\x03Tpm\x12\x19\n\x11manufacturer_info\x18\x01 \x01(\t\x12\x0f\n\x07version\x18\x02 \x01(\t\x1a\x93\x01\n\x06Stylus\x12=\n\x03usb\x18\x01 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.UsbH\x00\x12=\n\x03i2c\x18\x02 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.I2CH\x00\x42\x0b\n\tinterface\x1a$\n\x14\x44isplayPortConverter\x12\x0c\n\x04name\x18\x01 \x01(\t\x1aV\n\x08\x43\x65llular\x12=\n\x03usb\x18\x01 \x01(\x0b\x32..chromiumos.config.api.Component.Interface.UsbH\x00\x42\x0b\n\tinterface\x1a\x8a\x01\n\x07\x41lsStep\x12\x1c\n\x14\x61\x63_backlight_percent\x18\x01 \x01(\x01\x12!\n\x19\x62\x61ttery_backlight_percent\x18\x02 \x01(\x01\x12\x1e\n\x16lux_decrease_threshold\x18\x03 \x01(\x05\x12\x1e\n\x16lux_increase_threshold\x18\x04 \x01(\x05\"\x80\x01\n\rSupportStatus\x12\x12\n\x0eSTATUS_UNKNOWN\x10\x00\x12\x14\n\x10STATUS_SUPPORTED\x10\x01\x12\x15\n\x11STATUS_DEPRECATED\x10\x02\x12\x16\n\x12STATUS_UNQUALIFIED\x10\x03\x12\x16\n\x12STATUS_UNSUPPORTED\x10\x04\x42\x06\n\x04typeB*Z(go.chromium.org/chromiumos/config/go/apib\x06proto3'
   ,
-  dependencies=[chromiumos_dot_config_dot_api_dot_component__id__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_partner__id__pb2.DESCRIPTOR,])
+  dependencies=[chromiumos_dot_config_dot_api_dot_component__id__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_partner__id__pb2.DESCRIPTOR,google_dot_protobuf_dot_wrappers__pb2.DESCRIPTOR,])
 
 
 
@@ -55,8 +56,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2142,
-  serialized_end=2225,
+  serialized_start=2264,
+  serialized_end=2347,
 )
 _sym_db.RegisterEnumDescriptor(_COMPONENT_SOC_ARCHITECTURE)
 
@@ -74,11 +75,15 @@
       name='SMT', index=1, number=1,
       serialized_options=None,
       type=None),
+    _descriptor.EnumValueDescriptor(
+      name='SHA_NI', index=2, number=2,
+      serialized_options=None,
+      type=None),
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2227,
-  serialized_end=2266,
+  serialized_start=2349,
+  serialized_end=2400,
 )
 _sym_db.RegisterEnumDescriptor(_COMPONENT_SOC_FEATURE)
 
@@ -119,8 +124,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2480,
-  serialized_end=2571,
+  serialized_start=2614,
+  serialized_end=2705,
 )
 _sym_db.RegisterEnumDescriptor(_COMPONENT_MEMORY_TYPE)
 
@@ -141,8 +146,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2946,
-  serialized_end=2994,
+  serialized_start=3080,
+  serialized_end=3128,
 )
 _sym_db.RegisterEnumDescriptor(_COMPONENT_CAMERA_FEATURE)
 
@@ -167,8 +172,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2996,
-  serialized_end=3062,
+  serialized_start=3130,
+  serialized_end=3196,
 )
 _sym_db.RegisterEnumDescriptor(_COMPONENT_CAMERA_CLOCKTYPE)
 
@@ -189,8 +194,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=3368,
-  serialized_end=3407,
+  serialized_start=3731,
+  serialized_end=3770,
 )
 _sym_db.RegisterEnumDescriptor(_COMPONENT_DISPLAYPANEL_FEATURE)
 
@@ -215,8 +220,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=3629,
-  serialized_end=3684,
+  serialized_start=3992,
+  serialized_end=4047,
 )
 _sym_db.RegisterEnumDescriptor(_COMPONENT_TOUCH_TOUCHTYPE)
 
@@ -257,8 +262,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=3857,
-  serialized_end=4014,
+  serialized_start=4220,
+  serialized_end=4377,
 )
 _sym_db.RegisterEnumDescriptor(_COMPONENT_WIFI_WLANPROTOCOL)
 
@@ -287,8 +292,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=4176,
-  serialized_end=4261,
+  serialized_start=4539,
+  serialized_end=4624,
 )
 _sym_db.RegisterEnumDescriptor(_COMPONENT_QUALIFICATION_STATUS)
 
@@ -309,8 +314,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=4361,
-  serialized_end=4418,
+  serialized_start=4724,
+  serialized_end=4781,
 )
 _sym_db.RegisterEnumDescriptor(_COMPONENT_AMPLIFIER_FEATURE)
 
@@ -335,8 +340,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=4548,
-  serialized_end=4603,
+  serialized_start=4911,
+  serialized_end=4966,
 )
 _sym_db.RegisterEnumDescriptor(_COMPONENT_BATTERY_TECHNOLOGY)
 
@@ -365,11 +370,45 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=4876,
-  serialized_end=4945,
+  serialized_start=5302,
+  serialized_end=5371,
 )
 _sym_db.RegisterEnumDescriptor(_COMPONENT_STORAGE_STORAGETYPE)
 
+_COMPONENT_SUPPORTSTATUS = _descriptor.EnumDescriptor(
+  name='SupportStatus',
+  full_name='chromiumos.config.api.Component.SupportStatus',
+  filename=None,
+  file=DESCRIPTOR,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='STATUS_UNKNOWN', index=0, number=0,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='STATUS_SUPPORTED', index=1, number=1,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='STATUS_DEPRECATED', index=2, number=2,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='STATUS_UNQUALIFIED', index=3, number=3,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='STATUS_UNSUPPORTED', index=4, number=4,
+      serialized_options=None,
+      type=None),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=5855,
+  serialized_end=5983,
+)
+_sym_db.RegisterEnumDescriptor(_COMPONENT_SUPPORTSTATUS)
+
 
 _COMPONENT_AVLID = _descriptor.Descriptor(
   name='AVLId',
@@ -404,8 +443,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1669,
-  serialized_end=1702,
+  serialized_start=1773,
+  serialized_end=1806,
 )
 
 _COMPONENT_INTERFACE_I2C = _descriptor.Descriptor(
@@ -441,8 +480,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1718,
-  serialized_end=1756,
+  serialized_start=1822,
+  serialized_end=1860,
 )
 
 _COMPONENT_INTERFACE_USB = _descriptor.Descriptor(
@@ -485,8 +524,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1758,
-  serialized_end=1822,
+  serialized_start=1862,
+  serialized_end=1926,
 )
 
 _COMPONENT_INTERFACE_PCI = _descriptor.Descriptor(
@@ -517,6 +556,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='class_id', full_name='chromiumos.config.api.Component.Interface.Pci.class_id', index=3,
+      number=4, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -529,8 +575,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1824,
-  serialized_end=1888,
+  serialized_start=1928,
+  serialized_end=2010,
 )
 
 _COMPONENT_INTERFACE = _descriptor.Descriptor(
@@ -552,8 +598,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1705,
-  serialized_end=1888,
+  serialized_start=1809,
+  serialized_end=2010,
 )
 
 _COMPONENT_SOC_FAMILY = _descriptor.Descriptor(
@@ -589,8 +635,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2053,
-  serialized_end=2140,
+  serialized_start=2175,
+  serialized_end=2262,
 )
 
 _COMPONENT_SOC = _descriptor.Descriptor(
@@ -642,8 +688,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1891,
-  serialized_end=2266,
+  serialized_start=2013,
+  serialized_end=2400,
 )
 
 _COMPONENT_MEMORY_PROFILE = _descriptor.Descriptor(
@@ -686,8 +732,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2366,
-  serialized_end=2478,
+  serialized_start=2500,
+  serialized_end=2612,
 )
 
 _COMPONENT_MEMORY = _descriptor.Descriptor(
@@ -724,8 +770,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2269,
-  serialized_end=2577,
+  serialized_start=2403,
+  serialized_end=2711,
 )
 
 _COMPONENT_BLUETOOTH = _descriptor.Descriptor(
@@ -754,8 +800,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2579,
-  serialized_end=2669,
+  serialized_start=2713,
+  serialized_end=2803,
 )
 
 _COMPONENT_CAMERA = _descriptor.Descriptor(
@@ -810,8 +856,8 @@
       name='interface', full_name='chromiumos.config.api.Component.Camera.interface',
       index=0, containing_type=None, fields=[]),
   ],
-  serialized_start=2672,
-  serialized_end=3075,
+  serialized_start=2806,
+  serialized_end=3209,
 )
 
 _COMPONENT_DISPLAYPANEL_PROPERTIES = _descriptor.Descriptor(
@@ -856,6 +902,41 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='min_visible_backlight_level', full_name='chromiumos.config.api.Component.DisplayPanel.Properties.min_visible_backlight_level', index=5,
+      number=6, type=13, cpp_type=3, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='turn_off_screen_timeout_ms', full_name='chromiumos.config.api.Component.DisplayPanel.Properties.turn_off_screen_timeout_ms', index=6,
+      number=7, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='no_als_battery_brightness', full_name='chromiumos.config.api.Component.DisplayPanel.Properties.no_als_battery_brightness', index=7,
+      number=8, type=1, cpp_type=5, label=1,
+      has_default_value=False, default_value=float(0),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='no_als_ac_brightness', full_name='chromiumos.config.api.Component.DisplayPanel.Properties.no_als_ac_brightness', index=8,
+      number=9, type=1, cpp_type=5, label=1,
+      has_default_value=False, default_value=float(0),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='als_steps', full_name='chromiumos.config.api.Component.DisplayPanel.Properties.als_steps', index=9,
+      number=10, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -868,8 +949,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3193,
-  serialized_end=3366,
+  serialized_start=3327,
+  serialized_end=3729,
 )
 
 _COMPONENT_DISPLAYPANEL = _descriptor.Descriptor(
@@ -906,8 +987,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3078,
-  serialized_end=3407,
+  serialized_start=3212,
+  serialized_end=3770,
 )
 
 _COMPONENT_TOUCH = _descriptor.Descriptor(
@@ -972,8 +1053,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3410,
-  serialized_end=3696,
+  serialized_start=3773,
+  serialized_end=4059,
 )
 
 _COMPONENT_WIFI = _descriptor.Descriptor(
@@ -1013,8 +1094,8 @@
       name='interface', full_name='chromiumos.config.api.Component.Wifi.interface',
       index=0, containing_type=None, fields=[]),
   ],
-  serialized_start=3699,
-  serialized_end=4027,
+  serialized_start=4062,
+  serialized_end=4390,
 )
 
 _COMPONENT_QUALIFICATION = _descriptor.Descriptor(
@@ -1051,8 +1132,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4030,
-  serialized_end=4261,
+  serialized_start=4393,
+  serialized_end=4624,
 )
 
 _COMPONENT_AMPLIFIER = _descriptor.Descriptor(
@@ -1089,8 +1170,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4264,
-  serialized_end=4418,
+  serialized_start=4627,
+  serialized_end=4781,
 )
 
 _COMPONENT_AUDIOCODEC = _descriptor.Descriptor(
@@ -1119,8 +1200,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4420,
-  serialized_end=4446,
+  serialized_start=4783,
+  serialized_end=4809,
 )
 
 _COMPONENT_BATTERY = _descriptor.Descriptor(
@@ -1157,8 +1238,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4449,
-  serialized_end=4603,
+  serialized_start=4812,
+  serialized_end=4966,
 )
 
 _COMPONENT_FLASHCHIP = _descriptor.Descriptor(
@@ -1187,8 +1268,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4605,
-  serialized_end=4637,
+  serialized_start=4968,
+  serialized_end=5000,
 )
 
 _COMPONENT_EMBEDDEDCONTROLLER = _descriptor.Descriptor(
@@ -1217,8 +1298,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4639,
-  serialized_end=4680,
+  serialized_start=5002,
+  serialized_end=5043,
 )
 
 _COMPONENT_STORAGE = _descriptor.Descriptor(
@@ -1284,6 +1365,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='pci', full_name='chromiumos.config.api.Component.Storage.pci', index=8,
+      number=9, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -1296,9 +1384,12 @@
   syntax='proto3',
   extension_ranges=[],
   oneofs=[
+    _descriptor.OneofDescriptor(
+      name='interface', full_name='chromiumos.config.api.Component.Storage.interface',
+      index=0, containing_type=None, fields=[]),
   ],
-  serialized_start=4683,
-  serialized_end=4945,
+  serialized_start=5046,
+  serialized_end=5384,
 )
 
 _COMPONENT_TPM = _descriptor.Descriptor(
@@ -1334,8 +1425,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4947,
-  serialized_end=4996,
+  serialized_start=5386,
+  serialized_end=5435,
 )
 
 _COMPONENT_STYLUS = _descriptor.Descriptor(
@@ -1374,8 +1465,8 @@
       name='interface', full_name='chromiumos.config.api.Component.Stylus.interface',
       index=0, containing_type=None, fields=[]),
   ],
-  serialized_start=4999,
-  serialized_end=5146,
+  serialized_start=5438,
+  serialized_end=5585,
 )
 
 _COMPONENT_DISPLAYPORTCONVERTER = _descriptor.Descriptor(
@@ -1404,8 +1495,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5148,
-  serialized_end=5184,
+  serialized_start=5587,
+  serialized_end=5623,
 )
 
 _COMPONENT_CELLULAR = _descriptor.Descriptor(
@@ -1437,8 +1528,59 @@
       name='interface', full_name='chromiumos.config.api.Component.Cellular.interface',
       index=0, containing_type=None, fields=[]),
   ],
-  serialized_start=5186,
-  serialized_end=5272,
+  serialized_start=5625,
+  serialized_end=5711,
+)
+
+_COMPONENT_ALSSTEP = _descriptor.Descriptor(
+  name='AlsStep',
+  full_name='chromiumos.config.api.Component.AlsStep',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='ac_backlight_percent', full_name='chromiumos.config.api.Component.AlsStep.ac_backlight_percent', index=0,
+      number=1, type=1, cpp_type=5, label=1,
+      has_default_value=False, default_value=float(0),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='battery_backlight_percent', full_name='chromiumos.config.api.Component.AlsStep.battery_backlight_percent', index=1,
+      number=2, type=1, cpp_type=5, label=1,
+      has_default_value=False, default_value=float(0),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='lux_decrease_threshold', full_name='chromiumos.config.api.Component.AlsStep.lux_decrease_threshold', index=2,
+      number=3, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='lux_increase_threshold', full_name='chromiumos.config.api.Component.AlsStep.lux_increase_threshold', index=3,
+      number=4, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=5714,
+  serialized_end=5852,
 )
 
 _COMPONENT = _descriptor.Descriptor(
@@ -1498,140 +1640,147 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='soc', full_name='chromiumos.config.api.Component.soc', index=7,
+      name='support_status', full_name='chromiumos.config.api.Component.support_status', index=7,
+      number=28, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='soc', full_name='chromiumos.config.api.Component.soc', index=8,
       number=2, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='memory', full_name='chromiumos.config.api.Component.memory', index=8,
+      name='memory', full_name='chromiumos.config.api.Component.memory', index=9,
       number=3, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='bluetooth', full_name='chromiumos.config.api.Component.bluetooth', index=9,
+      name='bluetooth', full_name='chromiumos.config.api.Component.bluetooth', index=10,
       number=4, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='camera', full_name='chromiumos.config.api.Component.camera', index=10,
+      name='camera', full_name='chromiumos.config.api.Component.camera', index=11,
       number=5, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='touchscreen', full_name='chromiumos.config.api.Component.touchscreen', index=11,
+      name='touchscreen', full_name='chromiumos.config.api.Component.touchscreen', index=12,
       number=6, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='wifi', full_name='chromiumos.config.api.Component.wifi', index=12,
+      name='wifi', full_name='chromiumos.config.api.Component.wifi', index=13,
       number=7, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='touchpad', full_name='chromiumos.config.api.Component.touchpad', index=13,
+      name='touchpad', full_name='chromiumos.config.api.Component.touchpad', index=14,
       number=10, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='display_panel', full_name='chromiumos.config.api.Component.display_panel', index=14,
+      name='display_panel', full_name='chromiumos.config.api.Component.display_panel', index=15,
       number=11, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='audio_codec', full_name='chromiumos.config.api.Component.audio_codec', index=15,
+      name='audio_codec', full_name='chromiumos.config.api.Component.audio_codec', index=16,
       number=12, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='battery', full_name='chromiumos.config.api.Component.battery', index=16,
+      name='battery', full_name='chromiumos.config.api.Component.battery', index=17,
       number=13, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='ec_flash_chip', full_name='chromiumos.config.api.Component.ec_flash_chip', index=17,
+      name='ec_flash_chip', full_name='chromiumos.config.api.Component.ec_flash_chip', index=18,
       number=14, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='system_flash_chip', full_name='chromiumos.config.api.Component.system_flash_chip', index=18,
+      name='system_flash_chip', full_name='chromiumos.config.api.Component.system_flash_chip', index=19,
       number=15, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='ec', full_name='chromiumos.config.api.Component.ec', index=19,
+      name='ec', full_name='chromiumos.config.api.Component.ec', index=20,
       number=16, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='storage', full_name='chromiumos.config.api.Component.storage', index=20,
+      name='storage', full_name='chromiumos.config.api.Component.storage', index=21,
       number=17, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='tpm', full_name='chromiumos.config.api.Component.tpm', index=21,
+      name='tpm', full_name='chromiumos.config.api.Component.tpm', index=22,
       number=18, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='usb_host', full_name='chromiumos.config.api.Component.usb_host', index=22,
+      name='usb_host', full_name='chromiumos.config.api.Component.usb_host', index=23,
       number=19, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='stylus', full_name='chromiumos.config.api.Component.stylus', index=23,
+      name='stylus', full_name='chromiumos.config.api.Component.stylus', index=24,
       number=23, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='amplifier', full_name='chromiumos.config.api.Component.amplifier', index=24,
+      name='amplifier', full_name='chromiumos.config.api.Component.amplifier', index=25,
       number=24, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='dp_converter', full_name='chromiumos.config.api.Component.dp_converter', index=25,
+      name='dp_converter', full_name='chromiumos.config.api.Component.dp_converter', index=26,
       number=26, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='cellular', full_name='chromiumos.config.api.Component.cellular', index=26,
+      name='cellular', full_name='chromiumos.config.api.Component.cellular', index=27,
       number=27, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
@@ -1640,8 +1789,9 @@
   ],
   extensions=[
   ],
-  nested_types=[_COMPONENT_AVLID, _COMPONENT_INTERFACE, _COMPONENT_SOC, _COMPONENT_MEMORY, _COMPONENT_BLUETOOTH, _COMPONENT_CAMERA, _COMPONENT_DISPLAYPANEL, _COMPONENT_TOUCH, _COMPONENT_WIFI, _COMPONENT_QUALIFICATION, _COMPONENT_AMPLIFIER, _COMPONENT_AUDIOCODEC, _COMPONENT_BATTERY, _COMPONENT_FLASHCHIP, _COMPONENT_EMBEDDEDCONTROLLER, _COMPONENT_STORAGE, _COMPONENT_TPM, _COMPONENT_STYLUS, _COMPONENT_DISPLAYPORTCONVERTER, _COMPONENT_CELLULAR, ],
+  nested_types=[_COMPONENT_AVLID, _COMPONENT_INTERFACE, _COMPONENT_SOC, _COMPONENT_MEMORY, _COMPONENT_BLUETOOTH, _COMPONENT_CAMERA, _COMPONENT_DISPLAYPANEL, _COMPONENT_TOUCH, _COMPONENT_WIFI, _COMPONENT_QUALIFICATION, _COMPONENT_AMPLIFIER, _COMPONENT_AUDIOCODEC, _COMPONENT_BATTERY, _COMPONENT_FLASHCHIP, _COMPONENT_EMBEDDEDCONTROLLER, _COMPONENT_STORAGE, _COMPONENT_TPM, _COMPONENT_STYLUS, _COMPONENT_DISPLAYPORTCONVERTER, _COMPONENT_CELLULAR, _COMPONENT_ALSSTEP, ],
   enum_types=[
+    _COMPONENT_SUPPORTSTATUS,
   ],
   serialized_options=None,
   is_extendable=False,
@@ -1652,8 +1802,8 @@
       name='type', full_name='chromiumos.config.api.Component.type',
       index=0, containing_type=None, fields=[]),
   ],
-  serialized_start=147,
-  serialized_end=5280,
+  serialized_start=179,
+  serialized_end=5991,
 )
 
 _COMPONENT_AVLID.containing_type = _COMPONENT
@@ -1689,6 +1839,8 @@
   _COMPONENT_CAMERA.fields_by_name['pci'])
 _COMPONENT_CAMERA.fields_by_name['pci'].containing_oneof = _COMPONENT_CAMERA.oneofs_by_name['interface']
 _COMPONENT_DISPLAYPANEL_PROPERTIES.fields_by_name['features'].enum_type = _COMPONENT_DISPLAYPANEL_FEATURE
+_COMPONENT_DISPLAYPANEL_PROPERTIES.fields_by_name['turn_off_screen_timeout_ms'].message_type = google_dot_protobuf_dot_wrappers__pb2._UINT32VALUE
+_COMPONENT_DISPLAYPANEL_PROPERTIES.fields_by_name['als_steps'].message_type = _COMPONENT_ALSSTEP
 _COMPONENT_DISPLAYPANEL_PROPERTIES.containing_type = _COMPONENT_DISPLAYPANEL
 _COMPONENT_DISPLAYPANEL.fields_by_name['properties'].message_type = _COMPONENT_DISPLAYPANEL_PROPERTIES
 _COMPONENT_DISPLAYPANEL.containing_type = _COMPONENT
@@ -1718,8 +1870,12 @@
 _COMPONENT_FLASHCHIP.containing_type = _COMPONENT
 _COMPONENT_EMBEDDEDCONTROLLER.containing_type = _COMPONENT
 _COMPONENT_STORAGE.fields_by_name['type'].enum_type = _COMPONENT_STORAGE_STORAGETYPE
+_COMPONENT_STORAGE.fields_by_name['pci'].message_type = _COMPONENT_INTERFACE_PCI
 _COMPONENT_STORAGE.containing_type = _COMPONENT
 _COMPONENT_STORAGE_STORAGETYPE.containing_type = _COMPONENT_STORAGE
+_COMPONENT_STORAGE.oneofs_by_name['interface'].fields.append(
+  _COMPONENT_STORAGE.fields_by_name['pci'])
+_COMPONENT_STORAGE.fields_by_name['pci'].containing_oneof = _COMPONENT_STORAGE.oneofs_by_name['interface']
 _COMPONENT_TPM.containing_type = _COMPONENT
 _COMPONENT_STYLUS.fields_by_name['usb'].message_type = _COMPONENT_INTERFACE_USB
 _COMPONENT_STYLUS.fields_by_name['i2c'].message_type = _COMPONENT_INTERFACE_I2C
@@ -1736,9 +1892,11 @@
 _COMPONENT_CELLULAR.oneofs_by_name['interface'].fields.append(
   _COMPONENT_CELLULAR.fields_by_name['usb'])
 _COMPONENT_CELLULAR.fields_by_name['usb'].containing_oneof = _COMPONENT_CELLULAR.oneofs_by_name['interface']
+_COMPONENT_ALSSTEP.containing_type = _COMPONENT
 _COMPONENT.fields_by_name['id'].message_type = chromiumos_dot_config_dot_api_dot_component__id__pb2._COMPONENTID
 _COMPONENT.fields_by_name['manufacturer_id'].message_type = chromiumos_dot_config_dot_api_dot_partner__id__pb2._PARTNERID
 _COMPONENT.fields_by_name['avl_id'].message_type = _COMPONENT_AVLID
+_COMPONENT.fields_by_name['support_status'].enum_type = _COMPONENT_SUPPORTSTATUS
 _COMPONENT.fields_by_name['soc'].message_type = _COMPONENT_SOC
 _COMPONENT.fields_by_name['memory'].message_type = _COMPONENT_MEMORY
 _COMPONENT.fields_by_name['bluetooth'].message_type = _COMPONENT_BLUETOOTH
@@ -1759,6 +1917,7 @@
 _COMPONENT.fields_by_name['amplifier'].message_type = _COMPONENT_AMPLIFIER
 _COMPONENT.fields_by_name['dp_converter'].message_type = _COMPONENT_DISPLAYPORTCONVERTER
 _COMPONENT.fields_by_name['cellular'].message_type = _COMPONENT_CELLULAR
+_COMPONENT_SUPPORTSTATUS.containing_type = _COMPONENT
 _COMPONENT.oneofs_by_name['type'].fields.append(
   _COMPONENT.fields_by_name['soc'])
 _COMPONENT.fields_by_name['soc'].containing_oneof = _COMPONENT.oneofs_by_name['type']
@@ -2005,6 +2164,13 @@
     # @@protoc_insertion_point(class_scope:chromiumos.config.api.Component.Cellular)
     })
   ,
+
+  'AlsStep' : _reflection.GeneratedProtocolMessageType('AlsStep', (_message.Message,), {
+    'DESCRIPTOR' : _COMPONENT_ALSSTEP,
+    '__module__' : 'chromiumos.config.api.component_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.config.api.Component.AlsStep)
+    })
+  ,
   'DESCRIPTOR' : _COMPONENT,
   '__module__' : 'chromiumos.config.api.component_pb2'
   # @@protoc_insertion_point(class_scope:chromiumos.config.api.Component)
@@ -2036,6 +2202,7 @@
 _sym_db.RegisterMessage(Component.Stylus)
 _sym_db.RegisterMessage(Component.DisplayPortConverter)
 _sym_db.RegisterMessage(Component.Cellular)
+_sym_db.RegisterMessage(Component.AlsStep)
 
 
 DESCRIPTOR._options = None
diff --git a/api/gen_sdk/chromiumos/config/api/design_pb2.py b/api/gen_sdk/chromiumos/config/api/design_pb2.py
index 49c2fc2..7ff3ef7 100644
--- a/api/gen_sdk/chromiumos/config/api/design_pb2.py
+++ b/api/gen_sdk/chromiumos/config/api/design_pb2.py
@@ -25,7 +25,7 @@
   package='chromiumos.config.api',
   syntax='proto3',
   serialized_options=b'Z(go.chromium.org/chromiumos/config/go/api',
-  serialized_pb=b'\n\"chromiumos/config/api/design.proto\x12\x15\x63hromiumos.config.api\x1a,chromiumos/config/api/design_config_id.proto\x1a%chromiumos/config/api/design_id.proto\x1a-chromiumos/config/api/hardware_topology.proto\x1a&chromiumos/config/api/partner_id.proto\x1a&chromiumos/config/api/program_id.proto\x1a$chromiumos/config/api/topology.proto\x1a=chromiumos/config/public_replication/public_replication.proto\"\xb6\x08\n\x06\x44\x65sign\x12S\n\x12public_replication\x18\x07 \x01(\x0b\x32\x37.chromiumos.config.public_replication.PublicReplication\x12+\n\x02id\x18\x01 \x01(\x0b\x32\x1f.chromiumos.config.api.DesignId\x12\x34\n\nprogram_id\x18\x02 \x01(\x0b\x32 .chromiumos.config.api.ProgramId\x12\x30\n\x06odm_id\x18\x03 \x01(\x0b\x32 .chromiumos.config.api.PartnerId\x12\x0c\n\x04name\x18\x04 \x01(\t\x12G\n\x0e\x62oard_id_phase\x18\x05 \x03(\x0b\x32/.chromiumos.config.api.Design.BoardIdPhaseEntry\x12\x35\n\x07\x63onfigs\x18\x06 \x03(\x0b\x32$.chromiumos.config.api.Design.Config\x12@\n\nssfc_value\x18\x08 \x03(\x0b\x32,.chromiumos.config.api.Design.SsfcValueEntry\x1a\x33\n\x11\x42oardIdPhaseEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\x30\n\x0eSsfcValueEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\xfa\x03\n\x06\x43onfig\x12S\n\x12public_replication\x18\x05 \x01(\x0b\x32\x37.chromiumos.config.public_replication.PublicReplication\x12\x31\n\x02id\x18\x01 \x01(\x0b\x32%.chromiumos.config.api.DesignConfigId\x12\x42\n\x11hardware_topology\x18\x02 \x01(\x0b\x32\'.chromiumos.config.api.HardwareTopology\x12\x42\n\x11hardware_features\x18\x03 \x01(\x0b\x32\'.chromiumos.config.api.HardwareFeatures\x1a\xd3\x01\n\nConstraint\x12\x44\n\x05level\x18\x01 \x01(\x0e\x32\x35.chromiumos.config.api.Design.Config.Constraint.Level\x12\x39\n\x08\x66\x65\x61tures\x18\x02 \x01(\x0b\x32\'.chromiumos.config.api.HardwareFeatures\"D\n\x05Level\x12\x10\n\x0cTYPE_UNKNOWN\x10\x00\x12\x0c\n\x08REQUIRED\x10\x01\x12\r\n\tPREFERRED\x10\x02\x12\x0c\n\x08OPTIONAL\x10\x03J\x04\x08\x04\x10\x05J\x04\x08\x07\x10\x08J\x04\x08\t\x10\nR\x08platformB*Z(go.chromium.org/chromiumos/config/go/apib\x06proto3'
+  serialized_pb=b'\n\"chromiumos/config/api/design.proto\x12\x15\x63hromiumos.config.api\x1a,chromiumos/config/api/design_config_id.proto\x1a%chromiumos/config/api/design_id.proto\x1a-chromiumos/config/api/hardware_topology.proto\x1a&chromiumos/config/api/partner_id.proto\x1a&chromiumos/config/api/program_id.proto\x1a$chromiumos/config/api/topology.proto\x1a=chromiumos/config/public_replication/public_replication.proto\"\xaf\t\n\x06\x44\x65sign\x12S\n\x12public_replication\x18\x07 \x01(\x0b\x32\x37.chromiumos.config.public_replication.PublicReplication\x12+\n\x02id\x18\x01 \x01(\x0b\x32\x1f.chromiumos.config.api.DesignId\x12\x34\n\nprogram_id\x18\x02 \x01(\x0b\x32 .chromiumos.config.api.ProgramId\x12\x30\n\x06odm_id\x18\x03 \x01(\x0b\x32 .chromiumos.config.api.PartnerId\x12\x0c\n\x04name\x18\x04 \x01(\t\x12G\n\x0e\x62oard_id_phase\x18\x05 \x03(\x0b\x32/.chromiumos.config.api.Design.BoardIdPhaseEntry\x12\x35\n\x07\x63onfigs\x18\x06 \x03(\x0b\x32$.chromiumos.config.api.Design.Config\x12@\n\nssfc_value\x18\x08 \x03(\x0b\x32,.chromiumos.config.api.Design.SsfcValueEntry\x12=\n\x0b\x63ustom_type\x18\n \x01(\x0e\x32(.chromiumos.config.api.Design.CustomType\x1a\x33\n\x11\x42oardIdPhaseEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\x30\n\x0eSsfcValueEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\xfa\x03\n\x06\x43onfig\x12S\n\x12public_replication\x18\x05 \x01(\x0b\x32\x37.chromiumos.config.public_replication.PublicReplication\x12\x31\n\x02id\x18\x01 \x01(\x0b\x32%.chromiumos.config.api.DesignConfigId\x12\x42\n\x11hardware_topology\x18\x02 \x01(\x0b\x32\'.chromiumos.config.api.HardwareTopology\x12\x42\n\x11hardware_features\x18\x03 \x01(\x0b\x32\'.chromiumos.config.api.HardwareFeatures\x1a\xd3\x01\n\nConstraint\x12\x44\n\x05level\x18\x01 \x01(\x0e\x32\x35.chromiumos.config.api.Design.Config.Constraint.Level\x12\x39\n\x08\x66\x65\x61tures\x18\x02 \x01(\x0b\x32\'.chromiumos.config.api.HardwareFeatures\"D\n\x05Level\x12\x10\n\x0cTYPE_UNKNOWN\x10\x00\x12\x0c\n\x08REQUIRED\x10\x01\x12\r\n\tPREFERRED\x10\x02\x12\x0c\n\x08OPTIONAL\x10\x03J\x04\x08\x04\x10\x05J\x04\x08\x07\x10\x08\"8\n\nCustomType\x12\r\n\tNO_CUSTOM\x10\x00\x12\x0e\n\nWHITELABEL\x10\x01\x12\x0b\n\x07REBRAND\x10\x02J\x04\x08\t\x10\nR\x08platformB*Z(go.chromium.org/chromiumos/config/go/apib\x06proto3'
   ,
   dependencies=[chromiumos_dot_config_dot_api_dot_design__config__id__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_design__id__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_hardware__topology__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_partner__id__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_program__id__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_topology__pb2.DESCRIPTOR,chromiumos_dot_config_dot_public__replication_dot_public__replication__pb2.DESCRIPTOR,])
 
@@ -56,11 +56,37 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1357,
-  serialized_end=1425,
+  serialized_start=1420,
+  serialized_end=1488,
 )
 _sym_db.RegisterEnumDescriptor(_DESIGN_CONFIG_CONSTRAINT_LEVEL)
 
+_DESIGN_CUSTOMTYPE = _descriptor.EnumDescriptor(
+  name='CustomType',
+  full_name='chromiumos.config.api.Design.CustomType',
+  filename=None,
+  file=DESCRIPTOR,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='NO_CUSTOM', index=0, number=0,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='WHITELABEL', index=1, number=1,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='REBRAND', index=2, number=2,
+      serialized_options=None,
+      type=None),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=1502,
+  serialized_end=1558,
+)
+_sym_db.RegisterEnumDescriptor(_DESIGN_CUSTOMTYPE)
+
 
 _DESIGN_BOARDIDPHASEENTRY = _descriptor.Descriptor(
   name='BoardIdPhaseEntry',
@@ -95,8 +121,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=827,
-  serialized_end=878,
+  serialized_start=890,
+  serialized_end=941,
 )
 
 _DESIGN_SSFCVALUEENTRY = _descriptor.Descriptor(
@@ -132,8 +158,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=880,
-  serialized_end=928,
+  serialized_start=943,
+  serialized_end=991,
 )
 
 _DESIGN_CONFIG_CONSTRAINT = _descriptor.Descriptor(
@@ -170,8 +196,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1214,
-  serialized_end=1425,
+  serialized_start=1277,
+  serialized_end=1488,
 )
 
 _DESIGN_CONFIG = _descriptor.Descriptor(
@@ -221,8 +247,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=931,
-  serialized_end=1437,
+  serialized_start=994,
+  serialized_end=1500,
 )
 
 _DESIGN = _descriptor.Descriptor(
@@ -288,11 +314,19 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='custom_type', full_name='chromiumos.config.api.Design.custom_type', index=8,
+      number=10, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
   nested_types=[_DESIGN_BOARDIDPHASEENTRY, _DESIGN_SSFCVALUEENTRY, _DESIGN_CONFIG, ],
   enum_types=[
+    _DESIGN_CUSTOMTYPE,
   ],
   serialized_options=None,
   is_extendable=False,
@@ -301,7 +335,7 @@
   oneofs=[
   ],
   serialized_start=375,
-  serialized_end=1453,
+  serialized_end=1574,
 )
 
 _DESIGN_BOARDIDPHASEENTRY.containing_type = _DESIGN
@@ -322,6 +356,8 @@
 _DESIGN.fields_by_name['board_id_phase'].message_type = _DESIGN_BOARDIDPHASEENTRY
 _DESIGN.fields_by_name['configs'].message_type = _DESIGN_CONFIG
 _DESIGN.fields_by_name['ssfc_value'].message_type = _DESIGN_SSFCVALUEENTRY
+_DESIGN.fields_by_name['custom_type'].enum_type = _DESIGN_CUSTOMTYPE
+_DESIGN_CUSTOMTYPE.containing_type = _DESIGN
 DESCRIPTOR.message_types_by_name['Design'] = _DESIGN
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
diff --git a/api/gen_sdk/chromiumos/config/api/hardware_topology_pb2.py b/api/gen_sdk/chromiumos/config/api/hardware_topology_pb2.py
index 905d1fd..b63bd75 100644
--- a/api/gen_sdk/chromiumos/config/api/hardware_topology_pb2.py
+++ b/api/gen_sdk/chromiumos/config/api/hardware_topology_pb2.py
@@ -19,7 +19,7 @@
   package='chromiumos.config.api',
   syntax='proto3',
   serialized_options=b'Z(go.chromium.org/chromiumos/config/go/api',
-  serialized_pb=b'\n-chromiumos/config/api/hardware_topology.proto\x12\x15\x63hromiumos.config.api\x1a$chromiumos/config/api/topology.proto\"\xfa\n\n\x10HardwareTopology\x12/\n\x06screen\x18\x01 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x34\n\x0b\x66orm_factor\x18\x02 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12.\n\x05\x61udio\x18\x03 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12/\n\x06stylus\x18\x04 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x31\n\x08keyboard\x18\x05 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x30\n\x07thermal\x18\x06 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12/\n\x06\x63\x61mera\x18\x07 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12M\n$accelerometer_gyroscope_magnetometer\x18\x08 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x34\n\x0b\x66ingerprint\x18\t \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x39\n\x10proximity_sensor\x18\n \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x37\n\x0e\x64\x61ughter_board\x18\x0b \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12=\n\x14non_volatile_storage\x18\x0c \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12,\n\x03ram\x18\r \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12-\n\x04wifi\x18\x0e \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x32\n\tlte_board\x18\x0f \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x32\n\tsd_reader\x18\x10 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x38\n\x0fmotherboard_usb\x18\x11 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x32\n\tbluetooth\x18\x12 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x33\n\nbarreljack\x18\x13 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x35\n\x0cpower_button\x18\x14 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x36\n\rvolume_button\x18\x15 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12+\n\x02\x65\x63\x18\x16 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12.\n\x05touch\x18\x17 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12,\n\x03tpm\x18\x18 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12?\n\x16microphone_mute_switch\x18\x19 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12-\n\x04hdmi\x18\x1a \x01(\x0b\x32\x1f.chromiumos.config.api.TopologyB*Z(go.chromium.org/chromiumos/config/go/apib\x06proto3'
+  serialized_pb=b'\n-chromiumos/config/api/hardware_topology.proto\x12\x15\x63hromiumos.config.api\x1a$chromiumos/config/api/topology.proto\"\xc9\x0c\n\x10HardwareTopology\x12/\n\x06screen\x18\x01 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x34\n\x0b\x66orm_factor\x18\x02 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12.\n\x05\x61udio\x18\x03 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12/\n\x06stylus\x18\x04 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x31\n\x08keyboard\x18\x05 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x30\n\x07thermal\x18\x06 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12/\n\x06\x63\x61mera\x18\x07 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12M\n$accelerometer_gyroscope_magnetometer\x18\x08 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x34\n\x0b\x66ingerprint\x18\t \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x39\n\x10proximity_sensor\x18\n \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x37\n\x0e\x64\x61ughter_board\x18\x0b \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12=\n\x14non_volatile_storage\x18\x0c \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12,\n\x03ram\x18\r \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12-\n\x04wifi\x18\x0e \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x37\n\x0e\x63\x65llular_board\x18\x0f \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x32\n\tsd_reader\x18\x10 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x38\n\x0fmotherboard_usb\x18\x11 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x32\n\tbluetooth\x18\x12 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x33\n\nbarreljack\x18\x13 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x35\n\x0cpower_button\x18\x14 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x36\n\rvolume_button\x18\x15 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12+\n\x02\x65\x63\x18\x16 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12.\n\x05touch\x18\x17 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12,\n\x03tpm\x18\x18 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12?\n\x16microphone_mute_switch\x18\x19 \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12-\n\x04hdmi\x18\x1a \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12,\n\x03hps\x18\x1b \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x35\n\x0c\x64p_converter\x18\x1c \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12,\n\x03poe\x18\x1d \x01(\x0b\x32\x1f.chromiumos.config.api.Topology\x12\x35\n\x0cpower_supply\x18\x1e \x01(\x0b\x32\x1f.chromiumos.config.api.TopologyB*Z(go.chromium.org/chromiumos/config/go/apib\x06proto3'
   ,
   dependencies=[chromiumos_dot_config_dot_api_dot_topology__pb2.DESCRIPTOR,])
 
@@ -132,7 +132,7 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='lte_board', full_name='chromiumos.config.api.HardwareTopology.lte_board', index=14,
+      name='cellular_board', full_name='chromiumos.config.api.HardwareTopology.cellular_board', index=14,
       number=15, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
@@ -215,6 +215,34 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='hps', full_name='chromiumos.config.api.HardwareTopology.hps', index=26,
+      number=27, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='dp_converter', full_name='chromiumos.config.api.HardwareTopology.dp_converter', index=27,
+      number=28, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='poe', full_name='chromiumos.config.api.HardwareTopology.poe', index=28,
+      number=29, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='power_supply', full_name='chromiumos.config.api.HardwareTopology.power_supply', index=29,
+      number=30, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -228,7 +256,7 @@
   oneofs=[
   ],
   serialized_start=111,
-  serialized_end=1513,
+  serialized_end=1720,
 )
 
 _HARDWARETOPOLOGY.fields_by_name['screen'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
@@ -245,7 +273,7 @@
 _HARDWARETOPOLOGY.fields_by_name['non_volatile_storage'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
 _HARDWARETOPOLOGY.fields_by_name['ram'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
 _HARDWARETOPOLOGY.fields_by_name['wifi'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
-_HARDWARETOPOLOGY.fields_by_name['lte_board'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
+_HARDWARETOPOLOGY.fields_by_name['cellular_board'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
 _HARDWARETOPOLOGY.fields_by_name['sd_reader'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
 _HARDWARETOPOLOGY.fields_by_name['motherboard_usb'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
 _HARDWARETOPOLOGY.fields_by_name['bluetooth'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
@@ -257,6 +285,10 @@
 _HARDWARETOPOLOGY.fields_by_name['tpm'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
 _HARDWARETOPOLOGY.fields_by_name['microphone_mute_switch'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
 _HARDWARETOPOLOGY.fields_by_name['hdmi'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
+_HARDWARETOPOLOGY.fields_by_name['hps'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
+_HARDWARETOPOLOGY.fields_by_name['dp_converter'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
+_HARDWARETOPOLOGY.fields_by_name['poe'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
+_HARDWARETOPOLOGY.fields_by_name['power_supply'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._TOPOLOGY
 DESCRIPTOR.message_types_by_name['HardwareTopology'] = _HARDWARETOPOLOGY
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
diff --git a/api/gen_sdk/chromiumos/config/api/program_pb2.py b/api/gen_sdk/chromiumos/config/api/program_pb2.py
index 7f5ff17..58a0afc 100644
--- a/api/gen_sdk/chromiumos/config/api/program_pb2.py
+++ b/api/gen_sdk/chromiumos/config/api/program_pb2.py
@@ -16,6 +16,7 @@
 from chromite.api.gen_sdk.chromiumos.config.api import design_id_pb2 as chromiumos_dot_config_dot_api_dot_design__id__pb2
 from chromite.api.gen_sdk.chromiumos.config.api import device_brand_id_pb2 as chromiumos_dot_config_dot_api_dot_device__brand__id__pb2
 from chromite.api.gen_sdk.chromiumos.config.api import program_id_pb2 as chromiumos_dot_config_dot_api_dot_program__id__pb2
+from chromite.api.gen_sdk.chromiumos.config.api import topology_pb2 as chromiumos_dot_config_dot_api_dot_topology__pb2
 from chromite.api.gen_sdk.chromiumos.config.public_replication import public_replication_pb2 as chromiumos_dot_config_dot_public__replication_dot_public__replication__pb2
 
 
@@ -24,9 +25,9 @@
   package='chromiumos.config.api',
   syntax='proto3',
   serialized_options=b'Z(go.chromium.org/chromiumos/config/go/api',
-  serialized_pb=b'\n#chromiumos/config/api/program.proto\x12\x15\x63hromiumos.config.api\x1a%chromiumos/config/api/component.proto\x1a\"chromiumos/config/api/design.proto\x1a%chromiumos/config/api/design_id.proto\x1a+chromiumos/config/api/device_brand_id.proto\x1a&chromiumos/config/api/program_id.proto\x1a=chromiumos/config/public_replication/public_replication.proto\":\n\x1c\x46irmwareConfigurationSegment\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04mask\x18\x02 \x01(\r\"k\n\x15\x44\x65signConfigIdSegment\x12\x32\n\tdesign_id\x18\x01 \x01(\x0b\x32\x1f.chromiumos.config.api.DesignId\x12\x0e\n\x06min_id\x18\x02 \x01(\r\x12\x0e\n\x06max_id\x18\x03 \x01(\r\"\xa2\x01\n\x12\x44\x65viceSignerConfig\x12\x38\n\x08\x62rand_id\x18\x01 \x01(\x0b\x32$.chromiumos.config.api.DeviceBrandIdH\x00\x12\x34\n\tdesign_id\x18\x03 \x01(\x0b\x32\x1f.chromiumos.config.api.DesignIdH\x00\x12\x0e\n\x06key_id\x18\x02 \x01(\tB\x0c\n\nidentifier\"\x86\x0b\n\x07Program\x12S\n\x12public_replication\x18\x08 \x01(\x0b\x32\x37.chromiumos.config.public_replication.PublicReplication\x12,\n\x02id\x18\x01 \x01(\x0b\x32 .chromiumos.config.api.ProgramId\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x1b\n\x13mosys_platform_name\x18\n \x01(\t\x12\x39\n\x08platform\x18\x0b \x01(\x0b\x32\'.chromiumos.config.api.Program.Platform\x12R\n\x19\x64\x65sign_config_constraints\x18\x03 \x03(\x0b\x32/.chromiumos.config.api.Design.Config.Constraint\x12G\n\x0f\x63omponent_quals\x18\x04 \x03(\x0b\x32..chromiumos.config.api.Component.Qualification\x12\\\n\x1f\x66irmware_configuration_segments\x18\x05 \x03(\x0b\x32\x33.chromiumos.config.api.FirmwareConfigurationSegment\x12J\n\rssfc_segments\x18\t \x03(\x0b\x32\x33.chromiumos.config.api.FirmwareConfigurationSegment\x12O\n\x19\x64\x65sign_config_id_segments\x18\x07 \x03(\x0b\x32,.chromiumos.config.api.DesignConfigIdSegment\x12H\n\x15\x64\x65vice_signer_configs\x18\x06 \x03(\x0b\x32).chromiumos.config.api.DeviceSignerConfig\x1a\xaf\x05\n\x08Platform\x12\x12\n\nsoc_family\x18\x01 \x01(\t\x12>\n\x08soc_arch\x18\x02 \x01(\x0e\x32,.chromiumos.config.api.Program.Platform.Arch\x12\x12\n\ngpu_family\x18\x03 \x01(\t\x12J\n\rgraphics_apis\x18\x04 \x03(\x0e\x32\x33.chromiumos.config.api.Program.Platform.GraphicsApi\x12S\n\x0cvideo_codecs\x18\x05 \x03(\x0e\x32=.chromiumos.config.api.Program.Platform.AcceleratedVideoCodec\"A\n\x04\x41rch\x12\x10\n\x0c\x41RCH_UNKNOWN\x10\x00\x12\x07\n\x03X86\x10\x01\x12\n\n\x06X86_64\x10\x02\x12\x07\n\x03\x41RM\x10\x03\x12\t\n\x05\x41RM64\x10\x04\"\xf6\x01\n\x15\x41\x63\x63\x65leratedVideoCodec\x12\x13\n\x0f\x43ODEC_UNDEFINED\x10\x00\x12\x0f\n\x0bH264_DECODE\x10\x01\x12\x0f\n\x0bH264_ENCODE\x10\x02\x12\x0e\n\nVP8_DECODE\x10\x03\x12\x0e\n\nVP8_ENCODE\x10\x04\x12\x0e\n\nVP9_DECODE\x10\x05\x12\x0e\n\nVP9_ENCODE\x10\x06\x12\x10\n\x0cVP9_2_DECODE\x10\x07\x12\x10\n\x0cVP9_2_ENCODE\x10\x08\x12\x0f\n\x0bH265_DECODE\x10\t\x12\x0f\n\x0bH265_ENCODE\x10\n\x12\x0f\n\x0bMJPG_DECODE\x10\x0b\x12\x0f\n\x0bMJPG_ENCODE\x10\x0c\"^\n\x0bGraphicsApi\x12\x1a\n\x16GRAPHICS_API_UNDEFINED\x10\x00\x12\x17\n\x13GRAPHICS_API_OPENGL\x10\x01\x12\x1a\n\x16GRAPHICS_API_OPENGL_ES\x10\x02\x42*Z(go.chromium.org/chromiumos/config/go/apib\x06proto3'
+  serialized_pb=b'\n#chromiumos/config/api/program.proto\x12\x15\x63hromiumos.config.api\x1a%chromiumos/config/api/component.proto\x1a\"chromiumos/config/api/design.proto\x1a%chromiumos/config/api/design_id.proto\x1a+chromiumos/config/api/device_brand_id.proto\x1a&chromiumos/config/api/program_id.proto\x1a$chromiumos/config/api/topology.proto\x1a=chromiumos/config/public_replication/public_replication.proto\":\n\x1c\x46irmwareConfigurationSegment\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04mask\x18\x02 \x01(\r\"k\n\x15\x44\x65signConfigIdSegment\x12\x32\n\tdesign_id\x18\x01 \x01(\x0b\x32\x1f.chromiumos.config.api.DesignId\x12\x0e\n\x06min_id\x18\x02 \x01(\r\x12\x0e\n\x06max_id\x18\x03 \x01(\r\"\xa2\x01\n\x12\x44\x65viceSignerConfig\x12\x38\n\x08\x62rand_id\x18\x01 \x01(\x0b\x32$.chromiumos.config.api.DeviceBrandIdH\x00\x12\x34\n\tdesign_id\x18\x03 \x01(\x0b\x32\x1f.chromiumos.config.api.DesignIdH\x00\x12\x0e\n\x06key_id\x18\x02 \x01(\tB\x0c\n\nidentifier\"\xfb\r\n\x07Program\x12S\n\x12public_replication\x18\x08 \x01(\x0b\x32\x37.chromiumos.config.public_replication.PublicReplication\x12,\n\x02id\x18\x01 \x01(\x0b\x32 .chromiumos.config.api.ProgramId\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x1b\n\x13mosys_platform_name\x18\n \x01(\t\x12\x39\n\x08platform\x18\x0b \x01(\x0b\x32\'.chromiumos.config.api.Program.Platform\x12@\n\x0c\x61udio_config\x18\x0c \x01(\x0b\x32*.chromiumos.config.api.Program.AudioConfig\x12R\n\x19\x64\x65sign_config_constraints\x18\x03 \x03(\x0b\x32/.chromiumos.config.api.Design.Config.Constraint\x12G\n\x0f\x63omponent_quals\x18\x04 \x03(\x0b\x32..chromiumos.config.api.Component.Qualification\x12\\\n\x1f\x66irmware_configuration_segments\x18\x05 \x03(\x0b\x32\x33.chromiumos.config.api.FirmwareConfigurationSegment\x12J\n\rssfc_segments\x18\t \x03(\x0b\x32\x33.chromiumos.config.api.FirmwareConfigurationSegment\x12O\n\x19\x64\x65sign_config_id_segments\x18\x07 \x03(\x0b\x32,.chromiumos.config.api.DesignConfigIdSegment\x12H\n\x15\x64\x65vice_signer_configs\x18\x06 \x03(\x0b\x32).chromiumos.config.api.DeviceSignerConfig\x1a\xcd\x06\n\x08Platform\x12\x12\n\nsoc_family\x18\x01 \x01(\t\x12>\n\x08soc_arch\x18\x02 \x01(\x0e\x32,.chromiumos.config.api.Program.Platform.Arch\x12\x12\n\ngpu_family\x18\x03 \x01(\t\x12J\n\rgraphics_apis\x18\x04 \x03(\x0e\x32\x33.chromiumos.config.api.Program.Platform.GraphicsApi\x12S\n\x0cvideo_codecs\x18\x05 \x03(\x0e\x32=.chromiumos.config.api.Program.Platform.AcceleratedVideoCodec\x12J\n\x0c\x63\x61pabilities\x18\x06 \x01(\x0b\x32\x34.chromiumos.config.api.Program.Platform.Capabilities\x1aP\n\x0c\x43\x61pabilities\x12\x17\n\x0fsuspend_to_idle\x18\x01 \x01(\x08\x12\x13\n\x0b\x64\x61rk_resume\x18\x02 \x01(\x08\x12\x12\n\nwake_on_dp\x18\x03 \x01(\x08\"A\n\x04\x41rch\x12\x10\n\x0c\x41RCH_UNKNOWN\x10\x00\x12\x07\n\x03X86\x10\x01\x12\n\n\x06X86_64\x10\x02\x12\x07\n\x03\x41RM\x10\x03\x12\t\n\x05\x41RM64\x10\x04\"\xf6\x01\n\x15\x41\x63\x63\x65leratedVideoCodec\x12\x13\n\x0f\x43ODEC_UNDEFINED\x10\x00\x12\x0f\n\x0bH264_DECODE\x10\x01\x12\x0f\n\x0bH264_ENCODE\x10\x02\x12\x0e\n\nVP8_DECODE\x10\x03\x12\x0e\n\nVP8_ENCODE\x10\x04\x12\x0e\n\nVP9_DECODE\x10\x05\x12\x0e\n\nVP9_ENCODE\x10\x06\x12\x10\n\x0cVP9_2_DECODE\x10\x07\x12\x10\n\x0cVP9_2_ENCODE\x10\x08\x12\x0f\n\x0bH265_DECODE\x10\t\x12\x0f\n\x0bH265_ENCODE\x10\n\x12\x0f\n\x0bMJPG_DECODE\x10\x0b\x12\x0f\n\x0bMJPG_ENCODE\x10\x0c\"^\n\x0bGraphicsApi\x12\x1a\n\x16GRAPHICS_API_UNDEFINED\x10\x00\x12\x17\n\x13GRAPHICS_API_OPENGL\x10\x01\x12\x1a\n\x16GRAPHICS_API_OPENGL_ES\x10\x02\x1a\x92\x01\n\x0b\x41udioConfig\x12N\n\x0c\x63\x61rd_configs\x18\x01 \x03(\x0b\x32\x38.chromiumos.config.api.HardwareFeatures.Audio.CardConfig\x12\x17\n\x0fhas_module_file\x18\x02 \x01(\x08\x12\x1a\n\x12\x64\x65\x66\x61ult_ucm_suffix\x18\x03 \x01(\tB*Z(go.chromium.org/chromiumos/config/go/apib\x06proto3'
   ,
-  dependencies=[chromiumos_dot_config_dot_api_dot_component__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_design__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_design__id__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_device__brand__id__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_program__id__pb2.DESCRIPTOR,chromiumos_dot_config_dot_public__replication_dot_public__replication__pb2.DESCRIPTOR,])
+  dependencies=[chromiumos_dot_config_dot_api_dot_component__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_design__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_design__id__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_device__brand__id__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_program__id__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_topology__pb2.DESCRIPTOR,chromiumos_dot_config_dot_public__replication_dot_public__replication__pb2.DESCRIPTOR,])
 
 
 
@@ -59,8 +60,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1663,
-  serialized_end=1728,
+  serialized_start=1925,
+  serialized_end=1990,
 )
 _sym_db.RegisterEnumDescriptor(_PROGRAM_PLATFORM_ARCH)
 
@@ -125,8 +126,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1731,
-  serialized_end=1977,
+  serialized_start=1993,
+  serialized_end=2239,
 )
 _sym_db.RegisterEnumDescriptor(_PROGRAM_PLATFORM_ACCELERATEDVIDEOCODEC)
 
@@ -151,8 +152,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1979,
-  serialized_end=2073,
+  serialized_start=2241,
+  serialized_end=2335,
 )
 _sym_db.RegisterEnumDescriptor(_PROGRAM_PLATFORM_GRAPHICSAPI)
 
@@ -190,8 +191,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=324,
-  serialized_end=382,
+  serialized_start=362,
+  serialized_end=420,
 )
 
 
@@ -235,8 +236,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=384,
-  serialized_end=491,
+  serialized_start=422,
+  serialized_end=529,
 )
 
 
@@ -283,11 +284,55 @@
       name='identifier', full_name='chromiumos.config.api.DeviceSignerConfig.identifier',
       index=0, containing_type=None, fields=[]),
   ],
-  serialized_start=494,
-  serialized_end=656,
+  serialized_start=532,
+  serialized_end=694,
 )
 
 
+_PROGRAM_PLATFORM_CAPABILITIES = _descriptor.Descriptor(
+  name='Capabilities',
+  full_name='chromiumos.config.api.Program.Platform.Capabilities',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='suspend_to_idle', full_name='chromiumos.config.api.Program.Platform.Capabilities.suspend_to_idle', index=0,
+      number=1, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='dark_resume', full_name='chromiumos.config.api.Program.Platform.Capabilities.dark_resume', index=1,
+      number=2, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='wake_on_dp', full_name='chromiumos.config.api.Program.Platform.Capabilities.wake_on_dp', index=2,
+      number=3, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1843,
+  serialized_end=1923,
+)
+
 _PROGRAM_PLATFORM = _descriptor.Descriptor(
   name='Platform',
   full_name='chromiumos.config.api.Program.Platform',
@@ -330,10 +375,17 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='capabilities', full_name='chromiumos.config.api.Program.Platform.capabilities', index=5,
+      number=6, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
-  nested_types=[],
+  nested_types=[_PROGRAM_PLATFORM_CAPABILITIES, ],
   enum_types=[
     _PROGRAM_PLATFORM_ARCH,
     _PROGRAM_PLATFORM_ACCELERATEDVIDEOCODEC,
@@ -345,8 +397,52 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1386,
-  serialized_end=2073,
+  serialized_start=1490,
+  serialized_end=2335,
+)
+
+_PROGRAM_AUDIOCONFIG = _descriptor.Descriptor(
+  name='AudioConfig',
+  full_name='chromiumos.config.api.Program.AudioConfig',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='card_configs', full_name='chromiumos.config.api.Program.AudioConfig.card_configs', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='has_module_file', full_name='chromiumos.config.api.Program.AudioConfig.has_module_file', index=1,
+      number=2, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='default_ucm_suffix', full_name='chromiumos.config.api.Program.AudioConfig.default_ucm_suffix', index=2,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2338,
+  serialized_end=2484,
 )
 
 _PROGRAM = _descriptor.Descriptor(
@@ -392,42 +488,49 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='design_config_constraints', full_name='chromiumos.config.api.Program.design_config_constraints', index=5,
+      name='audio_config', full_name='chromiumos.config.api.Program.audio_config', index=5,
+      number=12, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='design_config_constraints', full_name='chromiumos.config.api.Program.design_config_constraints', index=6,
       number=3, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='component_quals', full_name='chromiumos.config.api.Program.component_quals', index=6,
+      name='component_quals', full_name='chromiumos.config.api.Program.component_quals', index=7,
       number=4, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='firmware_configuration_segments', full_name='chromiumos.config.api.Program.firmware_configuration_segments', index=7,
+      name='firmware_configuration_segments', full_name='chromiumos.config.api.Program.firmware_configuration_segments', index=8,
       number=5, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='ssfc_segments', full_name='chromiumos.config.api.Program.ssfc_segments', index=8,
+      name='ssfc_segments', full_name='chromiumos.config.api.Program.ssfc_segments', index=9,
       number=9, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='design_config_id_segments', full_name='chromiumos.config.api.Program.design_config_id_segments', index=9,
+      name='design_config_id_segments', full_name='chromiumos.config.api.Program.design_config_id_segments', index=10,
       number=7, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='device_signer_configs', full_name='chromiumos.config.api.Program.device_signer_configs', index=10,
+      name='device_signer_configs', full_name='chromiumos.config.api.Program.device_signer_configs', index=11,
       number=6, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
@@ -436,7 +539,7 @@
   ],
   extensions=[
   ],
-  nested_types=[_PROGRAM_PLATFORM, ],
+  nested_types=[_PROGRAM_PLATFORM, _PROGRAM_AUDIOCONFIG, ],
   enum_types=[
   ],
   serialized_options=None,
@@ -445,8 +548,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=659,
-  serialized_end=2073,
+  serialized_start=697,
+  serialized_end=2484,
 )
 
 _DESIGNCONFIGIDSEGMENT.fields_by_name['design_id'].message_type = chromiumos_dot_config_dot_api_dot_design__id__pb2._DESIGNID
@@ -458,16 +561,21 @@
 _DEVICESIGNERCONFIG.oneofs_by_name['identifier'].fields.append(
   _DEVICESIGNERCONFIG.fields_by_name['design_id'])
 _DEVICESIGNERCONFIG.fields_by_name['design_id'].containing_oneof = _DEVICESIGNERCONFIG.oneofs_by_name['identifier']
+_PROGRAM_PLATFORM_CAPABILITIES.containing_type = _PROGRAM_PLATFORM
 _PROGRAM_PLATFORM.fields_by_name['soc_arch'].enum_type = _PROGRAM_PLATFORM_ARCH
 _PROGRAM_PLATFORM.fields_by_name['graphics_apis'].enum_type = _PROGRAM_PLATFORM_GRAPHICSAPI
 _PROGRAM_PLATFORM.fields_by_name['video_codecs'].enum_type = _PROGRAM_PLATFORM_ACCELERATEDVIDEOCODEC
+_PROGRAM_PLATFORM.fields_by_name['capabilities'].message_type = _PROGRAM_PLATFORM_CAPABILITIES
 _PROGRAM_PLATFORM.containing_type = _PROGRAM
 _PROGRAM_PLATFORM_ARCH.containing_type = _PROGRAM_PLATFORM
 _PROGRAM_PLATFORM_ACCELERATEDVIDEOCODEC.containing_type = _PROGRAM_PLATFORM
 _PROGRAM_PLATFORM_GRAPHICSAPI.containing_type = _PROGRAM_PLATFORM
+_PROGRAM_AUDIOCONFIG.fields_by_name['card_configs'].message_type = chromiumos_dot_config_dot_api_dot_topology__pb2._HARDWAREFEATURES_AUDIO_CARDCONFIG
+_PROGRAM_AUDIOCONFIG.containing_type = _PROGRAM
 _PROGRAM.fields_by_name['public_replication'].message_type = chromiumos_dot_config_dot_public__replication_dot_public__replication__pb2._PUBLICREPLICATION
 _PROGRAM.fields_by_name['id'].message_type = chromiumos_dot_config_dot_api_dot_program__id__pb2._PROGRAMID
 _PROGRAM.fields_by_name['platform'].message_type = _PROGRAM_PLATFORM
+_PROGRAM.fields_by_name['audio_config'].message_type = _PROGRAM_AUDIOCONFIG
 _PROGRAM.fields_by_name['design_config_constraints'].message_type = chromiumos_dot_config_dot_api_dot_design__pb2._DESIGN_CONFIG_CONSTRAINT
 _PROGRAM.fields_by_name['component_quals'].message_type = chromiumos_dot_config_dot_api_dot_component__pb2._COMPONENT_QUALIFICATION
 _PROGRAM.fields_by_name['firmware_configuration_segments'].message_type = _FIRMWARECONFIGURATIONSEGMENT
@@ -504,17 +612,33 @@
 Program = _reflection.GeneratedProtocolMessageType('Program', (_message.Message,), {
 
   'Platform' : _reflection.GeneratedProtocolMessageType('Platform', (_message.Message,), {
+
+    'Capabilities' : _reflection.GeneratedProtocolMessageType('Capabilities', (_message.Message,), {
+      'DESCRIPTOR' : _PROGRAM_PLATFORM_CAPABILITIES,
+      '__module__' : 'chromiumos.config.api.program_pb2'
+      # @@protoc_insertion_point(class_scope:chromiumos.config.api.Program.Platform.Capabilities)
+      })
+    ,
     'DESCRIPTOR' : _PROGRAM_PLATFORM,
     '__module__' : 'chromiumos.config.api.program_pb2'
     # @@protoc_insertion_point(class_scope:chromiumos.config.api.Program.Platform)
     })
   ,
+
+  'AudioConfig' : _reflection.GeneratedProtocolMessageType('AudioConfig', (_message.Message,), {
+    'DESCRIPTOR' : _PROGRAM_AUDIOCONFIG,
+    '__module__' : 'chromiumos.config.api.program_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.config.api.Program.AudioConfig)
+    })
+  ,
   'DESCRIPTOR' : _PROGRAM,
   '__module__' : 'chromiumos.config.api.program_pb2'
   # @@protoc_insertion_point(class_scope:chromiumos.config.api.Program)
   })
 _sym_db.RegisterMessage(Program)
 _sym_db.RegisterMessage(Program.Platform)
+_sym_db.RegisterMessage(Program.Platform.Capabilities)
+_sym_db.RegisterMessage(Program.AudioConfig)
 
 
 DESCRIPTOR._options = None
diff --git a/api/gen_sdk/chromiumos/config/api/software/health_config_pb2.py b/api/gen_sdk/chromiumos/config/api/software/health_config_pb2.py
new file mode 100644
index 0000000..4a75818
--- /dev/null
+++ b/api/gen_sdk/chromiumos/config/api/software/health_config_pb2.py
@@ -0,0 +1,156 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: chromiumos/config/api/software/health_config.proto
+
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='chromiumos/config/api/software/health_config.proto',
+  package='chromiumos.config.api.software',
+  syntax='proto3',
+  serialized_options=b'Z1go.chromium.org/chromiumos/config/go/api/software',
+  serialized_pb=b'\n2chromiumos/config/api/software/health_config.proto\x12\x1e\x63hromiumos.config.api.software\"\xf1\x01\n\x0cHealthConfig\x12\x45\n\x07\x62\x61ttery\x18\x01 \x01(\x0b\x32\x34.chromiumos.config.api.software.HealthConfig.Battery\x12J\n\ncached_vpd\x18\x02 \x01(\x0b\x32\x36.chromiumos.config.api.software.HealthConfig.CachedVpd\x1a)\n\x07\x42\x61ttery\x12\x1e\n\x16has_smart_battery_info\x18\x01 \x01(\x08\x1a#\n\tCachedVpd\x12\x16\n\x0ehas_sku_number\x18\x01 \x01(\x08\x42\x33Z1go.chromium.org/chromiumos/config/go/api/softwareb\x06proto3'
+)
+
+
+
+
+_HEALTHCONFIG_BATTERY = _descriptor.Descriptor(
+  name='Battery',
+  full_name='chromiumos.config.api.software.HealthConfig.Battery',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='has_smart_battery_info', full_name='chromiumos.config.api.software.HealthConfig.Battery.has_smart_battery_info', index=0,
+      number=1, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=250,
+  serialized_end=291,
+)
+
+_HEALTHCONFIG_CACHEDVPD = _descriptor.Descriptor(
+  name='CachedVpd',
+  full_name='chromiumos.config.api.software.HealthConfig.CachedVpd',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='has_sku_number', full_name='chromiumos.config.api.software.HealthConfig.CachedVpd.has_sku_number', index=0,
+      number=1, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=293,
+  serialized_end=328,
+)
+
+_HEALTHCONFIG = _descriptor.Descriptor(
+  name='HealthConfig',
+  full_name='chromiumos.config.api.software.HealthConfig',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='battery', full_name='chromiumos.config.api.software.HealthConfig.battery', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='cached_vpd', full_name='chromiumos.config.api.software.HealthConfig.cached_vpd', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[_HEALTHCONFIG_BATTERY, _HEALTHCONFIG_CACHEDVPD, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=87,
+  serialized_end=328,
+)
+
+_HEALTHCONFIG_BATTERY.containing_type = _HEALTHCONFIG
+_HEALTHCONFIG_CACHEDVPD.containing_type = _HEALTHCONFIG
+_HEALTHCONFIG.fields_by_name['battery'].message_type = _HEALTHCONFIG_BATTERY
+_HEALTHCONFIG.fields_by_name['cached_vpd'].message_type = _HEALTHCONFIG_CACHEDVPD
+DESCRIPTOR.message_types_by_name['HealthConfig'] = _HEALTHCONFIG
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+HealthConfig = _reflection.GeneratedProtocolMessageType('HealthConfig', (_message.Message,), {
+
+  'Battery' : _reflection.GeneratedProtocolMessageType('Battery', (_message.Message,), {
+    'DESCRIPTOR' : _HEALTHCONFIG_BATTERY,
+    '__module__' : 'chromiumos.config.api.software.health_config_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.config.api.software.HealthConfig.Battery)
+    })
+  ,
+
+  'CachedVpd' : _reflection.GeneratedProtocolMessageType('CachedVpd', (_message.Message,), {
+    'DESCRIPTOR' : _HEALTHCONFIG_CACHEDVPD,
+    '__module__' : 'chromiumos.config.api.software.health_config_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.config.api.software.HealthConfig.CachedVpd)
+    })
+  ,
+  'DESCRIPTOR' : _HEALTHCONFIG,
+  '__module__' : 'chromiumos.config.api.software.health_config_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.config.api.software.HealthConfig)
+  })
+_sym_db.RegisterMessage(HealthConfig)
+_sym_db.RegisterMessage(HealthConfig.Battery)
+_sym_db.RegisterMessage(HealthConfig.CachedVpd)
+
+
+DESCRIPTOR._options = None
+# @@protoc_insertion_point(module_scope)
diff --git a/api/gen_sdk/chromiumos/config/api/software/software_config_pb2.py b/api/gen_sdk/chromiumos/config/api/software/software_config_pb2.py
index 3c76193..22b6275 100644
--- a/api/gen_sdk/chromiumos/config/api/software/software_config_pb2.py
+++ b/api/gen_sdk/chromiumos/config/api/software/software_config_pb2.py
@@ -17,9 +17,10 @@
 from chromite.api.gen_sdk.chromiumos.config.api import design_config_id_pb2 as chromiumos_dot_config_dot_api_dot_design__config__id__pb2
 from chromite.api.gen_sdk.chromiumos.config.api.software import audio_config_pb2 as chromiumos_dot_config_dot_api_dot_software_dot_audio__config__pb2
 from chromite.api.gen_sdk.chromiumos.config.api.software import bluetooth_config_pb2 as chromiumos_dot_config_dot_api_dot_software_dot_bluetooth__config__pb2
+from chromite.api.gen_sdk.chromiumos.config.api.software import camera_config_pb2 as chromiumos_dot_config_dot_api_dot_software_dot_camera__config__pb2
+from chromite.api.gen_sdk.chromiumos.config.api.software import health_config_pb2 as chromiumos_dot_config_dot_api_dot_software_dot_health__config__pb2
 from chromite.api.gen_sdk.chromiumos.config.api.software import power_config_pb2 as chromiumos_dot_config_dot_api_dot_software_dot_power__config__pb2
 from chromite.api.gen_sdk.chromiumos.config.api.software import wifi_config_pb2 as chromiumos_dot_config_dot_api_dot_software_dot_wifi__config__pb2
-from chromite.api.gen_sdk.chromiumos.config.api.software import camera_config_pb2 as chromiumos_dot_config_dot_api_dot_software_dot_camera__config__pb2
 from chromite.api.gen_sdk.chromiumos.config.api.software import ui_config_pb2 as chromiumos_dot_config_dot_api_dot_software_dot_ui__config__pb2
 from chromite.api.gen_sdk.chromiumos.config.public_replication import public_replication_pb2 as chromiumos_dot_config_dot_public__replication_dot_public__replication__pb2
 
@@ -29,9 +30,9 @@
   package='chromiumos.config.api.software',
   syntax='proto3',
   serialized_options=b'Z1go.chromium.org/chromiumos/config/go/api/software',
-  serialized_pb=b'\n4chromiumos/config/api/software/software_config.proto\x12\x1e\x63hromiumos.config.api.software\x1a\"chromiumos/build/api/factory.proto\x1a*chromiumos/build/api/firmware_config.proto\x1a\'chromiumos/build/api/system_image.proto\x1a,chromiumos/config/api/design_config_id.proto\x1a\x31\x63hromiumos/config/api/software/audio_config.proto\x1a\x35\x63hromiumos/config/api/software/bluetooth_config.proto\x1a\x31\x63hromiumos/config/api/software/power_config.proto\x1a\x30\x63hromiumos/config/api/software/wifi_config.proto\x1a\x32\x63hromiumos/config/api/software/camera_config.proto\x1a.chromiumos/config/api/software/ui_config.proto\x1a=chromiumos/config/public_replication/public_replication.proto\"\xfb\x07\n\x0eSoftwareConfig\x12S\n\x12public_replication\x18\x0c \x01(\x0b\x32\x37.chromiumos.config.public_replication.PublicReplication\x12?\n\x10\x64\x65sign_config_id\x18\x07 \x01(\x0b\x32%.chromiumos.config.api.DesignConfigId\x12H\n\x0eid_scan_config\x18\x08 \x01(\x0b\x32\x30.chromiumos.config.api.DesignConfigId.ScanConfig\x12\x36\n\x08\x66irmware\x18\x03 \x01(\x0b\x32$.chromiumos.build.api.FirmwareConfig\x12H\n\x15\x66irmware_build_config\x18\t \x01(\x0b\x32).chromiumos.build.api.FirmwareBuildConfig\x12K\n\x16\x66irmware_build_targets\x18\x10 \x01(\x0b\x32+.chromiumos.build.api.Firmware.BuildTargets\x12J\n\x13system_build_target\x18\r \x01(\x0b\x32-.chromiumos.build.api.SystemImage.BuildTarget\x12G\n\x14\x66\x61\x63tory_build_target\x18\x0e \x01(\x0b\x32).chromiumos.build.api.Factory.BuildTarget\x12I\n\x10\x62luetooth_config\x18\x04 \x01(\x0b\x32/.chromiumos.config.api.software.BluetoothConfig\x12\x41\n\x0cpower_config\x18\x05 \x01(\x0b\x32+.chromiumos.config.api.software.PowerConfig\x12\x42\n\raudio_configs\x18\n \x03(\x0b\x32+.chromiumos.config.api.software.AudioConfig\x12?\n\x0bwifi_config\x18\x0b \x01(\x0b\x32*.chromiumos.config.api.software.WifiConfig\x12\x43\n\rcamera_config\x18\x0f \x01(\x0b\x32,.chromiumos.config.api.software.CameraConfig\x12;\n\tui_config\x18\x11 \x01(\x0b\x32(.chromiumos.config.api.software.UiConfigJ\x04\x08\x01\x10\x02J\x04\x08\x02\x10\x03J\x04\x08\x06\x10\x07\x42\x33Z1go.chromium.org/chromiumos/config/go/api/softwareb\x06proto3'
+  serialized_pb=b'\n4chromiumos/config/api/software/software_config.proto\x12\x1e\x63hromiumos.config.api.software\x1a\"chromiumos/build/api/factory.proto\x1a*chromiumos/build/api/firmware_config.proto\x1a\'chromiumos/build/api/system_image.proto\x1a,chromiumos/config/api/design_config_id.proto\x1a\x31\x63hromiumos/config/api/software/audio_config.proto\x1a\x35\x63hromiumos/config/api/software/bluetooth_config.proto\x1a\x32\x63hromiumos/config/api/software/camera_config.proto\x1a\x32\x63hromiumos/config/api/software/health_config.proto\x1a\x31\x63hromiumos/config/api/software/power_config.proto\x1a\x30\x63hromiumos/config/api/software/wifi_config.proto\x1a.chromiumos/config/api/software/ui_config.proto\x1a=chromiumos/config/public_replication/public_replication.proto\"\xc0\x08\n\x0eSoftwareConfig\x12S\n\x12public_replication\x18\x0c \x01(\x0b\x32\x37.chromiumos.config.public_replication.PublicReplication\x12?\n\x10\x64\x65sign_config_id\x18\x07 \x01(\x0b\x32%.chromiumos.config.api.DesignConfigId\x12H\n\x0eid_scan_config\x18\x08 \x01(\x0b\x32\x30.chromiumos.config.api.DesignConfigId.ScanConfig\x12\x36\n\x08\x66irmware\x18\x03 \x01(\x0b\x32$.chromiumos.build.api.FirmwareConfig\x12H\n\x15\x66irmware_build_config\x18\t \x01(\x0b\x32).chromiumos.build.api.FirmwareBuildConfig\x12K\n\x16\x66irmware_build_targets\x18\x10 \x01(\x0b\x32+.chromiumos.build.api.Firmware.BuildTargets\x12J\n\x13system_build_target\x18\r \x01(\x0b\x32-.chromiumos.build.api.SystemImage.BuildTarget\x12G\n\x14\x66\x61\x63tory_build_target\x18\x0e \x01(\x0b\x32).chromiumos.build.api.Factory.BuildTarget\x12I\n\x10\x62luetooth_config\x18\x04 \x01(\x0b\x32/.chromiumos.config.api.software.BluetoothConfig\x12\x41\n\x0cpower_config\x18\x05 \x01(\x0b\x32+.chromiumos.config.api.software.PowerConfig\x12\x42\n\raudio_configs\x18\n \x03(\x0b\x32+.chromiumos.config.api.software.AudioConfig\x12?\n\x0bwifi_config\x18\x0b \x01(\x0b\x32*.chromiumos.config.api.software.WifiConfig\x12\x43\n\rhealth_config\x18\x12 \x01(\x0b\x32,.chromiumos.config.api.software.HealthConfig\x12\x43\n\rcamera_config\x18\x0f \x01(\x0b\x32,.chromiumos.config.api.software.CameraConfig\x12;\n\tui_config\x18\x11 \x01(\x0b\x32(.chromiumos.config.api.software.UiConfigJ\x04\x08\x01\x10\x02J\x04\x08\x02\x10\x03J\x04\x08\x06\x10\x07\x42\x33Z1go.chromium.org/chromiumos/config/go/api/softwareb\x06proto3'
   ,
-  dependencies=[chromiumos_dot_build_dot_api_dot_factory__pb2.DESCRIPTOR,chromiumos_dot_build_dot_api_dot_firmware__config__pb2.DESCRIPTOR,chromiumos_dot_build_dot_api_dot_system__image__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_design__config__id__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_software_dot_audio__config__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_software_dot_bluetooth__config__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_software_dot_power__config__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_software_dot_wifi__config__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_software_dot_camera__config__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_software_dot_ui__config__pb2.DESCRIPTOR,chromiumos_dot_config_dot_public__replication_dot_public__replication__pb2.DESCRIPTOR,])
+  dependencies=[chromiumos_dot_build_dot_api_dot_factory__pb2.DESCRIPTOR,chromiumos_dot_build_dot_api_dot_firmware__config__pb2.DESCRIPTOR,chromiumos_dot_build_dot_api_dot_system__image__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_design__config__id__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_software_dot_audio__config__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_software_dot_bluetooth__config__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_software_dot_camera__config__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_software_dot_health__config__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_software_dot_power__config__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_software_dot_wifi__config__pb2.DESCRIPTOR,chromiumos_dot_config_dot_api_dot_software_dot_ui__config__pb2.DESCRIPTOR,chromiumos_dot_config_dot_public__replication_dot_public__replication__pb2.DESCRIPTOR,])
 
 
 
@@ -128,14 +129,21 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='camera_config', full_name='chromiumos.config.api.software.SoftwareConfig.camera_config', index=12,
+      name='health_config', full_name='chromiumos.config.api.software.SoftwareConfig.health_config', index=12,
+      number=18, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='camera_config', full_name='chromiumos.config.api.software.SoftwareConfig.camera_config', index=13,
       number=15, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='ui_config', full_name='chromiumos.config.api.software.SoftwareConfig.ui_config', index=13,
+      name='ui_config', full_name='chromiumos.config.api.software.SoftwareConfig.ui_config', index=14,
       number=17, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
@@ -153,8 +161,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=626,
-  serialized_end=1645,
+  serialized_start=678,
+  serialized_end=1766,
 )
 
 _SOFTWARECONFIG.fields_by_name['public_replication'].message_type = chromiumos_dot_config_dot_public__replication_dot_public__replication__pb2._PUBLICREPLICATION
@@ -169,6 +177,7 @@
 _SOFTWARECONFIG.fields_by_name['power_config'].message_type = chromiumos_dot_config_dot_api_dot_software_dot_power__config__pb2._POWERCONFIG
 _SOFTWARECONFIG.fields_by_name['audio_configs'].message_type = chromiumos_dot_config_dot_api_dot_software_dot_audio__config__pb2._AUDIOCONFIG
 _SOFTWARECONFIG.fields_by_name['wifi_config'].message_type = chromiumos_dot_config_dot_api_dot_software_dot_wifi__config__pb2._WIFICONFIG
+_SOFTWARECONFIG.fields_by_name['health_config'].message_type = chromiumos_dot_config_dot_api_dot_software_dot_health__config__pb2._HEALTHCONFIG
 _SOFTWARECONFIG.fields_by_name['camera_config'].message_type = chromiumos_dot_config_dot_api_dot_software_dot_camera__config__pb2._CAMERACONFIG
 _SOFTWARECONFIG.fields_by_name['ui_config'].message_type = chromiumos_dot_config_dot_api_dot_software_dot_ui__config__pb2._UICONFIG
 DESCRIPTOR.message_types_by_name['SoftwareConfig'] = _SOFTWARECONFIG
diff --git a/api/gen_sdk/chromiumos/config/api/software/wifi_config_pb2.py b/api/gen_sdk/chromiumos/config/api/software/wifi_config_pb2.py
index fb912fb..053c5aa 100644
--- a/api/gen_sdk/chromiumos/config/api/software/wifi_config_pb2.py
+++ b/api/gen_sdk/chromiumos/config/api/software/wifi_config_pb2.py
@@ -18,7 +18,7 @@
   package='chromiumos.config.api.software',
   syntax='proto3',
   serialized_options=b'Z1go.chromium.org/chromiumos/config/go/api/software',
-  serialized_pb=b'\n0chromiumos/config/api/software/wifi_config.proto\x12\x1e\x63hromiumos.config.api.software\"\xc7$\n\nWifiConfig\x12P\n\rath10k_config\x18\x01 \x01(\x0b\x32\x37.chromiumos.config.api.software.WifiConfig.Ath10kConfigH\x00\x12N\n\x0crtw88_config\x18\x02 \x01(\x0b\x32\x36.chromiumos.config.api.software.WifiConfig.Rtw88ConfigH\x00\x12N\n\x0cintel_config\x18\x03 \x01(\x0b\x32\x36.chromiumos.config.api.software.WifiConfig.IntelConfigH\x00\x1a\xa6\x02\n\x0c\x41th10kConfig\x12k\n\x17tablet_mode_power_table\x18\x01 \x01(\x0b\x32J.chromiumos.config.api.software.WifiConfig.Ath10kConfig.TransmitPowerChain\x12o\n\x1bnon_tablet_mode_power_table\x18\x02 \x01(\x0b\x32J.chromiumos.config.api.software.WifiConfig.Ath10kConfig.TransmitPowerChain\x1a\x38\n\x12TransmitPowerChain\x12\x10\n\x08limit_2g\x18\x01 \x01(\r\x12\x10\n\x08limit_5g\x18\x02 \x01(\r\x1a\x87\x05\n\x0bRtw88Config\x12j\n\x17tablet_mode_power_table\x18\x01 \x01(\x0b\x32I.chromiumos.config.api.software.WifiConfig.Rtw88Config.TransmitPowerChain\x12n\n\x1bnon_tablet_mode_power_table\x18\x02 \x01(\x0b\x32I.chromiumos.config.api.software.WifiConfig.Rtw88Config.TransmitPowerChain\x12U\n\noffset_fcc\x18\x03 \x01(\x0b\x32\x41.chromiumos.config.api.software.WifiConfig.Rtw88Config.GeoOffsets\x12T\n\toffset_eu\x18\x04 \x01(\x0b\x32\x41.chromiumos.config.api.software.WifiConfig.Rtw88Config.GeoOffsets\x12W\n\x0coffset_other\x18\x05 \x01(\x0b\x32\x41.chromiumos.config.api.software.WifiConfig.Rtw88Config.GeoOffsets\x1a\x62\n\x12TransmitPowerChain\x12\x10\n\x08limit_2g\x18\x01 \x01(\r\x12\x12\n\nlimit_5g_1\x18\x02 \x01(\r\x12\x12\n\nlimit_5g_3\x18\x03 \x01(\r\x12\x12\n\nlimit_5g_4\x18\x04 \x01(\r\x1a\x32\n\nGeoOffsets\x12\x11\n\toffset_2g\x18\x01 \x01(\r\x12\x11\n\toffset_5g\x18\x02 \x01(\r\x1a\x84\x1b\n\x0bIntelConfig\x12R\n\tsar_table\x18\x01 \x01(\x0b\x32?.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable\x12R\n\nwgds_table\x18\x02 \x01(\x0b\x32>.chromiumos.config.api.software.WifiConfig.IntelConfig.Offsets\x12O\n\tant_table\x18\x03 \x01(\x0b\x32<.chromiumos.config.api.software.WifiConfig.IntelConfig.Gains\x12R\n\nwtas_table\x18\x04 \x01(\x0b\x32>.chromiumos.config.api.software.WifiConfig.IntelConfig.Average\x12G\n\x03\x64sm\x18\x05 \x01(\x0b\x32:.chromiumos.config.api.software.WifiConfig.IntelConfig.DSM\x1a\xee\t\n\x08SarTable\x12\x19\n\x11sar_table_version\x18\x01 \x01(\r\x12u\n\x19tablet_mode_power_table_a\x18\x03 \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x12u\n\x19tablet_mode_power_table_b\x18\x04 \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x12y\n\x1dnon_tablet_mode_power_table_a\x18\x05 \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x12y\n\x1dnon_tablet_mode_power_table_b\x18\x06 \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x12y\n\x1d\x63\x64\x62_tablet_mode_power_table_a\x18\x07 \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x12y\n\x1d\x63\x64\x62_tablet_mode_power_table_b\x18\x08 \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x12}\n!cdb_non_tablet_mode_power_table_a\x18\t \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x12}\n!cdb_non_tablet_mode_power_table_b\x18\n \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x1a\xee\x01\n\x12TransmitPowerChain\x12\x10\n\x08limit_2g\x18\x01 \x01(\r\x12\x12\n\nlimit_5g_1\x18\x02 \x01(\r\x12\x12\n\nlimit_5g_2\x18\x03 \x01(\r\x12\x12\n\nlimit_5g_3\x18\x04 \x01(\r\x12\x12\n\nlimit_5g_4\x18\x05 \x01(\r\x12\x12\n\nlimit_5g_5\x18\x06 \x01(\r\x12\x12\n\nlimit_6g_1\x18\x07 \x01(\r\x12\x12\n\nlimit_6g_2\x18\x08 \x01(\r\x12\x12\n\nlimit_6g_3\x18\t \x01(\r\x12\x12\n\nlimit_6g_4\x18\n \x01(\r\x12\x12\n\nlimit_6g_5\x18\x0b \x01(\r\x1a\xfa\x03\n\x07Offsets\x12\x14\n\x0cwgds_version\x18\x01 \x01(\r\x12]\n\noffset_fcc\x18\x02 \x01(\x0b\x32I.chromiumos.config.api.software.WifiConfig.IntelConfig.Offsets.GeoOffsets\x12\\\n\toffset_eu\x18\x03 \x01(\x0b\x32I.chromiumos.config.api.software.WifiConfig.IntelConfig.Offsets.GeoOffsets\x12_\n\x0coffset_other\x18\x04 \x01(\x0b\x32I.chromiumos.config.api.software.WifiConfig.IntelConfig.Offsets.GeoOffsets\x1a\xba\x01\n\nGeoOffsets\x12\x0e\n\x06max_2g\x18\x01 \x01(\r\x12\x13\n\x0boffset_2g_a\x18\x02 \x01(\r\x12\x13\n\x0boffset_2g_b\x18\x03 \x01(\r\x12\x0e\n\x06max_5g\x18\x04 \x01(\r\x12\x13\n\x0boffset_5g_a\x18\x05 \x01(\r\x12\x13\n\x0boffset_5g_b\x18\x06 \x01(\r\x12\x0e\n\x06max_6g\x18\x07 \x01(\r\x12\x13\n\x0boffset_6g_a\x18\x08 \x01(\r\x12\x13\n\x0boffset_6g_b\x18\t \x01(\r\x1a\x8c\x04\n\x05Gains\x12\x19\n\x11\x61nt_table_version\x18\x01 \x01(\r\x12\x15\n\rant_mode_ppag\x18\x02 \x01(\r\x12\x62\n\x10\x61nt_gain_table_a\x18\x03 \x01(\x0b\x32H.chromiumos.config.api.software.WifiConfig.IntelConfig.Gains.AntennaGain\x12\x62\n\x10\x61nt_gain_table_b\x18\x04 \x01(\x0b\x32H.chromiumos.config.api.software.WifiConfig.IntelConfig.Gains.AntennaGain\x1a\x88\x02\n\x0b\x41ntennaGain\x12\x13\n\x0b\x61nt_gain_2g\x18\x01 \x01(\r\x12\x15\n\rant_gain_5g_1\x18\x02 \x01(\r\x12\x15\n\rant_gain_5g_2\x18\x03 \x01(\r\x12\x15\n\rant_gain_5g_3\x18\x04 \x01(\r\x12\x15\n\rant_gain_5g_4\x18\x05 \x01(\r\x12\x15\n\rant_gain_5g_5\x18\x06 \x01(\r\x12\x15\n\rant_gain_6g_1\x18\x07 \x01(\r\x12\x15\n\rant_gain_6g_2\x18\x08 \x01(\r\x12\x15\n\rant_gain_6g_3\x18\t \x01(\r\x12\x15\n\rant_gain_6g_4\x18\n \x01(\r\x12\x15\n\rant_gain_6g_5\x18\x0b \x01(\r\x1a\x87\x04\n\x07\x41verage\x12\x17\n\x0fsar_avg_version\x18\x01 \x01(\r\x12\x15\n\rtas_selection\x18\x02 \x01(\r\x12\x15\n\rtas_list_size\x18\x03 \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_1\x18\x04 \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_2\x18\x05 \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_3\x18\x06 \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_4\x18\x07 \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_5\x18\x08 \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_6\x18\t \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_7\x18\n \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_8\x18\x0b \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_9\x18\x0c \x01(\r\x12\x1a\n\x12\x64\x65ny_list_entry_10\x18\r \x01(\r\x12\x1a\n\x12\x64\x65ny_list_entry_11\x18\x0e \x01(\r\x12\x1a\n\x12\x64\x65ny_list_entry_12\x18\x0f \x01(\r\x12\x1a\n\x12\x64\x65ny_list_entry_13\x18\x10 \x01(\r\x12\x1a\n\x12\x64\x65ny_list_entry_14\x18\x11 \x01(\r\x12\x1a\n\x12\x64\x65ny_list_entry_15\x18\x12 \x01(\r\x12\x1a\n\x12\x64\x65ny_list_entry_16\x18\x13 \x01(\r\x1a\xd7\x01\n\x03\x44SM\x12#\n\x1b\x64isable_active_sdr_channels\x18\x02 \x01(\x03\x12!\n\x19support_indonesia_5g_band\x18\x03 \x01(\x03\x12\x1f\n\x17support_ultra_high_band\x18\x04 \x01(\x03\x12!\n\x19regulatory_configurations\x18\x05 \x01(\x03\x12\x1b\n\x13uart_configurations\x18\x06 \x01(\x03\x12\x17\n\x0f\x65nablement_11ax\x18\x07 \x01(\x03\x12\x0e\n\x06unii_4\x18\x08 \x01(\x03\x42\r\n\x0bwifi_configB3Z1go.chromium.org/chromiumos/config/go/api/softwareb\x06proto3'
+  serialized_pb=b'\n0chromiumos/config/api/software/wifi_config.proto\x12\x1e\x63hromiumos.config.api.software\"\x84+\n\nWifiConfig\x12P\n\rath10k_config\x18\x01 \x01(\x0b\x32\x37.chromiumos.config.api.software.WifiConfig.Ath10kConfigH\x00\x12N\n\x0crtw88_config\x18\x02 \x01(\x0b\x32\x36.chromiumos.config.api.software.WifiConfig.Rtw88ConfigH\x00\x12N\n\x0cintel_config\x18\x03 \x01(\x0b\x32\x36.chromiumos.config.api.software.WifiConfig.IntelConfigH\x00\x12J\n\nmtk_config\x18\x04 \x01(\x0b\x32\x34.chromiumos.config.api.software.WifiConfig.MtkConfigH\x00\x1a\xa6\x02\n\x0c\x41th10kConfig\x12k\n\x17tablet_mode_power_table\x18\x01 \x01(\x0b\x32J.chromiumos.config.api.software.WifiConfig.Ath10kConfig.TransmitPowerChain\x12o\n\x1bnon_tablet_mode_power_table\x18\x02 \x01(\x0b\x32J.chromiumos.config.api.software.WifiConfig.Ath10kConfig.TransmitPowerChain\x1a\x38\n\x12TransmitPowerChain\x12\x10\n\x08limit_2g\x18\x01 \x01(\r\x12\x10\n\x08limit_5g\x18\x02 \x01(\r\x1a\x87\x05\n\x0bRtw88Config\x12j\n\x17tablet_mode_power_table\x18\x01 \x01(\x0b\x32I.chromiumos.config.api.software.WifiConfig.Rtw88Config.TransmitPowerChain\x12n\n\x1bnon_tablet_mode_power_table\x18\x02 \x01(\x0b\x32I.chromiumos.config.api.software.WifiConfig.Rtw88Config.TransmitPowerChain\x12U\n\noffset_fcc\x18\x03 \x01(\x0b\x32\x41.chromiumos.config.api.software.WifiConfig.Rtw88Config.GeoOffsets\x12T\n\toffset_eu\x18\x04 \x01(\x0b\x32\x41.chromiumos.config.api.software.WifiConfig.Rtw88Config.GeoOffsets\x12W\n\x0coffset_other\x18\x05 \x01(\x0b\x32\x41.chromiumos.config.api.software.WifiConfig.Rtw88Config.GeoOffsets\x1a\x62\n\x12TransmitPowerChain\x12\x10\n\x08limit_2g\x18\x01 \x01(\r\x12\x12\n\nlimit_5g_1\x18\x02 \x01(\r\x12\x12\n\nlimit_5g_3\x18\x03 \x01(\r\x12\x12\n\nlimit_5g_4\x18\x04 \x01(\r\x1a\x32\n\nGeoOffsets\x12\x11\n\toffset_2g\x18\x01 \x01(\r\x12\x11\n\toffset_5g\x18\x02 \x01(\r\x1a\x84\x1b\n\x0bIntelConfig\x12R\n\tsar_table\x18\x01 \x01(\x0b\x32?.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable\x12R\n\nwgds_table\x18\x02 \x01(\x0b\x32>.chromiumos.config.api.software.WifiConfig.IntelConfig.Offsets\x12O\n\tant_table\x18\x03 \x01(\x0b\x32<.chromiumos.config.api.software.WifiConfig.IntelConfig.Gains\x12R\n\nwtas_table\x18\x04 \x01(\x0b\x32>.chromiumos.config.api.software.WifiConfig.IntelConfig.Average\x12G\n\x03\x64sm\x18\x05 \x01(\x0b\x32:.chromiumos.config.api.software.WifiConfig.IntelConfig.DSM\x1a\xee\t\n\x08SarTable\x12\x19\n\x11sar_table_version\x18\x01 \x01(\r\x12u\n\x19tablet_mode_power_table_a\x18\x03 \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x12u\n\x19tablet_mode_power_table_b\x18\x04 \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x12y\n\x1dnon_tablet_mode_power_table_a\x18\x05 \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x12y\n\x1dnon_tablet_mode_power_table_b\x18\x06 \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x12y\n\x1d\x63\x64\x62_tablet_mode_power_table_a\x18\x07 \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x12y\n\x1d\x63\x64\x62_tablet_mode_power_table_b\x18\x08 \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x12}\n!cdb_non_tablet_mode_power_table_a\x18\t \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x12}\n!cdb_non_tablet_mode_power_table_b\x18\n \x01(\x0b\x32R.chromiumos.config.api.software.WifiConfig.IntelConfig.SarTable.TransmitPowerChain\x1a\xee\x01\n\x12TransmitPowerChain\x12\x10\n\x08limit_2g\x18\x01 \x01(\r\x12\x12\n\nlimit_5g_1\x18\x02 \x01(\r\x12\x12\n\nlimit_5g_2\x18\x03 \x01(\r\x12\x12\n\nlimit_5g_3\x18\x04 \x01(\r\x12\x12\n\nlimit_5g_4\x18\x05 \x01(\r\x12\x12\n\nlimit_5g_5\x18\x06 \x01(\r\x12\x12\n\nlimit_6g_1\x18\x07 \x01(\r\x12\x12\n\nlimit_6g_2\x18\x08 \x01(\r\x12\x12\n\nlimit_6g_3\x18\t \x01(\r\x12\x12\n\nlimit_6g_4\x18\n \x01(\r\x12\x12\n\nlimit_6g_5\x18\x0b \x01(\r\x1a\xfa\x03\n\x07Offsets\x12\x14\n\x0cwgds_version\x18\x01 \x01(\r\x12]\n\noffset_fcc\x18\x02 \x01(\x0b\x32I.chromiumos.config.api.software.WifiConfig.IntelConfig.Offsets.GeoOffsets\x12\\\n\toffset_eu\x18\x03 \x01(\x0b\x32I.chromiumos.config.api.software.WifiConfig.IntelConfig.Offsets.GeoOffsets\x12_\n\x0coffset_other\x18\x04 \x01(\x0b\x32I.chromiumos.config.api.software.WifiConfig.IntelConfig.Offsets.GeoOffsets\x1a\xba\x01\n\nGeoOffsets\x12\x0e\n\x06max_2g\x18\x01 \x01(\r\x12\x13\n\x0boffset_2g_a\x18\x02 \x01(\r\x12\x13\n\x0boffset_2g_b\x18\x03 \x01(\r\x12\x0e\n\x06max_5g\x18\x04 \x01(\r\x12\x13\n\x0boffset_5g_a\x18\x05 \x01(\r\x12\x13\n\x0boffset_5g_b\x18\x06 \x01(\r\x12\x0e\n\x06max_6g\x18\x07 \x01(\r\x12\x13\n\x0boffset_6g_a\x18\x08 \x01(\r\x12\x13\n\x0boffset_6g_b\x18\t \x01(\r\x1a\x8c\x04\n\x05Gains\x12\x19\n\x11\x61nt_table_version\x18\x01 \x01(\r\x12\x15\n\rant_mode_ppag\x18\x02 \x01(\r\x12\x62\n\x10\x61nt_gain_table_a\x18\x03 \x01(\x0b\x32H.chromiumos.config.api.software.WifiConfig.IntelConfig.Gains.AntennaGain\x12\x62\n\x10\x61nt_gain_table_b\x18\x04 \x01(\x0b\x32H.chromiumos.config.api.software.WifiConfig.IntelConfig.Gains.AntennaGain\x1a\x88\x02\n\x0b\x41ntennaGain\x12\x13\n\x0b\x61nt_gain_2g\x18\x01 \x01(\r\x12\x15\n\rant_gain_5g_1\x18\x02 \x01(\r\x12\x15\n\rant_gain_5g_2\x18\x03 \x01(\r\x12\x15\n\rant_gain_5g_3\x18\x04 \x01(\r\x12\x15\n\rant_gain_5g_4\x18\x05 \x01(\r\x12\x15\n\rant_gain_5g_5\x18\x06 \x01(\r\x12\x15\n\rant_gain_6g_1\x18\x07 \x01(\r\x12\x15\n\rant_gain_6g_2\x18\x08 \x01(\r\x12\x15\n\rant_gain_6g_3\x18\t \x01(\r\x12\x15\n\rant_gain_6g_4\x18\n \x01(\r\x12\x15\n\rant_gain_6g_5\x18\x0b \x01(\r\x1a\x87\x04\n\x07\x41verage\x12\x17\n\x0fsar_avg_version\x18\x01 \x01(\r\x12\x15\n\rtas_selection\x18\x02 \x01(\r\x12\x15\n\rtas_list_size\x18\x03 \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_1\x18\x04 \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_2\x18\x05 \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_3\x18\x06 \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_4\x18\x07 \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_5\x18\x08 \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_6\x18\t \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_7\x18\n \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_8\x18\x0b \x01(\r\x12\x19\n\x11\x64\x65ny_list_entry_9\x18\x0c \x01(\r\x12\x1a\n\x12\x64\x65ny_list_entry_10\x18\r \x01(\r\x12\x1a\n\x12\x64\x65ny_list_entry_11\x18\x0e \x01(\r\x12\x1a\n\x12\x64\x65ny_list_entry_12\x18\x0f \x01(\r\x12\x1a\n\x12\x64\x65ny_list_entry_13\x18\x10 \x01(\r\x12\x1a\n\x12\x64\x65ny_list_entry_14\x18\x11 \x01(\r\x12\x1a\n\x12\x64\x65ny_list_entry_15\x18\x12 \x01(\r\x12\x1a\n\x12\x64\x65ny_list_entry_16\x18\x13 \x01(\r\x1a\xd7\x01\n\x03\x44SM\x12#\n\x1b\x64isable_active_sdr_channels\x18\x02 \x01(\x03\x12!\n\x19support_indonesia_5g_band\x18\x03 \x01(\x03\x12\x1f\n\x17support_ultra_high_band\x18\x04 \x01(\x03\x12!\n\x19regulatory_configurations\x18\x05 \x01(\x03\x12\x1b\n\x13uart_configurations\x18\x06 \x01(\x03\x12\x17\n\x0f\x65nablement_11ax\x18\x07 \x01(\x03\x12\x0e\n\x06unii_4\x18\x08 \x01(\x03\x1a\xee\x05\n\tMtkConfig\x12h\n\x17tablet_mode_power_table\x18\x01 \x01(\x0b\x32G.chromiumos.config.api.software.WifiConfig.MtkConfig.TransmitPowerChain\x12l\n\x1bnon_tablet_mode_power_table\x18\x02 \x01(\x0b\x32G.chromiumos.config.api.software.WifiConfig.MtkConfig.TransmitPowerChain\x12\x63\n\x0f\x66\x63\x63_power_table\x18\x03 \x01(\x0b\x32J.chromiumos.config.api.software.WifiConfig.MtkConfig.GeoTransmitPowerChain\x12\x62\n\x0e\x65u_power_table\x18\x04 \x01(\x0b\x32J.chromiumos.config.api.software.WifiConfig.MtkConfig.GeoTransmitPowerChain\x12\x65\n\x11other_power_table\x18\x05 \x01(\x0b\x32J.chromiumos.config.api.software.WifiConfig.MtkConfig.GeoTransmitPowerChain\x1av\n\x12TransmitPowerChain\x12\x10\n\x08limit_2g\x18\x01 \x01(\r\x12\x12\n\nlimit_5g_1\x18\x02 \x01(\r\x12\x12\n\nlimit_5g_2\x18\x03 \x01(\r\x12\x12\n\nlimit_5g_3\x18\x04 \x01(\r\x12\x12\n\nlimit_5g_4\x18\x05 \x01(\r\x1a\x61\n\x15GeoTransmitPowerChain\x12\x10\n\x08limit_2g\x18\x01 \x01(\r\x12\x10\n\x08limit_5g\x18\x02 \x01(\r\x12\x11\n\toffset_2g\x18\x03 \x01(\r\x12\x11\n\toffset_5g\x18\x04 \x01(\rB\r\n\x0bwifi_configB3Z1go.chromium.org/chromiumos/config/go/api/softwareb\x06proto3'
 )
 
 
@@ -57,8 +57,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=580,
-  serialized_end=636,
+  serialized_start=656,
+  serialized_end=712,
 )
 
 _WIFICONFIG_ATH10KCONFIG = _descriptor.Descriptor(
@@ -94,8 +94,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=342,
-  serialized_end=636,
+  serialized_start=418,
+  serialized_end=712,
 )
 
 _WIFICONFIG_RTW88CONFIG_TRANSMITPOWERCHAIN = _descriptor.Descriptor(
@@ -145,8 +145,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1136,
-  serialized_end=1234,
+  serialized_start=1212,
+  serialized_end=1310,
 )
 
 _WIFICONFIG_RTW88CONFIG_GEOOFFSETS = _descriptor.Descriptor(
@@ -182,8 +182,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1236,
-  serialized_end=1286,
+  serialized_start=1312,
+  serialized_end=1362,
 )
 
 _WIFICONFIG_RTW88CONFIG = _descriptor.Descriptor(
@@ -240,8 +240,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=639,
-  serialized_end=1286,
+  serialized_start=715,
+  serialized_end=1362,
 )
 
 _WIFICONFIG_INTELCONFIG_SARTABLE_TRANSMITPOWERCHAIN = _descriptor.Descriptor(
@@ -340,8 +340,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2735,
-  serialized_end=2973,
+  serialized_start=2811,
+  serialized_end=3049,
 )
 
 _WIFICONFIG_INTELCONFIG_SARTABLE = _descriptor.Descriptor(
@@ -426,8 +426,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1711,
-  serialized_end=2973,
+  serialized_start=1787,
+  serialized_end=3049,
 )
 
 _WIFICONFIG_INTELCONFIG_OFFSETS_GEOOFFSETS = _descriptor.Descriptor(
@@ -512,8 +512,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3296,
-  serialized_end=3482,
+  serialized_start=3372,
+  serialized_end=3558,
 )
 
 _WIFICONFIG_INTELCONFIG_OFFSETS = _descriptor.Descriptor(
@@ -563,8 +563,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2976,
-  serialized_end=3482,
+  serialized_start=3052,
+  serialized_end=3558,
 )
 
 _WIFICONFIG_INTELCONFIG_GAINS_ANTENNAGAIN = _descriptor.Descriptor(
@@ -663,8 +663,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3745,
-  serialized_end=4009,
+  serialized_start=3821,
+  serialized_end=4085,
 )
 
 _WIFICONFIG_INTELCONFIG_GAINS = _descriptor.Descriptor(
@@ -714,8 +714,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3485,
-  serialized_end=4009,
+  serialized_start=3561,
+  serialized_end=4085,
 )
 
 _WIFICONFIG_INTELCONFIG_AVERAGE = _descriptor.Descriptor(
@@ -870,8 +870,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4012,
-  serialized_end=4531,
+  serialized_start=4088,
+  serialized_end=4607,
 )
 
 _WIFICONFIG_INTELCONFIG_DSM = _descriptor.Descriptor(
@@ -942,8 +942,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4534,
-  serialized_end=4749,
+  serialized_start=4610,
+  serialized_end=4825,
 )
 
 _WIFICONFIG_INTELCONFIG = _descriptor.Descriptor(
@@ -1000,8 +1000,175 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1289,
-  serialized_end=4749,
+  serialized_start=1365,
+  serialized_end=4825,
+)
+
+_WIFICONFIG_MTKCONFIG_TRANSMITPOWERCHAIN = _descriptor.Descriptor(
+  name='TransmitPowerChain',
+  full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.TransmitPowerChain',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='limit_2g', full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.TransmitPowerChain.limit_2g', index=0,
+      number=1, type=13, cpp_type=3, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='limit_5g_1', full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.TransmitPowerChain.limit_5g_1', index=1,
+      number=2, type=13, cpp_type=3, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='limit_5g_2', full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.TransmitPowerChain.limit_5g_2', index=2,
+      number=3, type=13, cpp_type=3, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='limit_5g_3', full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.TransmitPowerChain.limit_5g_3', index=3,
+      number=4, type=13, cpp_type=3, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='limit_5g_4', full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.TransmitPowerChain.limit_5g_4', index=4,
+      number=5, type=13, cpp_type=3, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2811,
+  serialized_end=2929,
+)
+
+_WIFICONFIG_MTKCONFIG_GEOTRANSMITPOWERCHAIN = _descriptor.Descriptor(
+  name='GeoTransmitPowerChain',
+  full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.GeoTransmitPowerChain',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='limit_2g', full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.GeoTransmitPowerChain.limit_2g', index=0,
+      number=1, type=13, cpp_type=3, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='limit_5g', full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.GeoTransmitPowerChain.limit_5g', index=1,
+      number=2, type=13, cpp_type=3, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='offset_2g', full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.GeoTransmitPowerChain.offset_2g', index=2,
+      number=3, type=13, cpp_type=3, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='offset_5g', full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.GeoTransmitPowerChain.offset_5g', index=3,
+      number=4, type=13, cpp_type=3, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=5481,
+  serialized_end=5578,
+)
+
+_WIFICONFIG_MTKCONFIG = _descriptor.Descriptor(
+  name='MtkConfig',
+  full_name='chromiumos.config.api.software.WifiConfig.MtkConfig',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='tablet_mode_power_table', full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.tablet_mode_power_table', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='non_tablet_mode_power_table', full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.non_tablet_mode_power_table', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='fcc_power_table', full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.fcc_power_table', index=2,
+      number=3, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='eu_power_table', full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.eu_power_table', index=3,
+      number=4, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='other_power_table', full_name='chromiumos.config.api.software.WifiConfig.MtkConfig.other_power_table', index=4,
+      number=5, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[_WIFICONFIG_MTKCONFIG_TRANSMITPOWERCHAIN, _WIFICONFIG_MTKCONFIG_GEOTRANSMITPOWERCHAIN, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=4828,
+  serialized_end=5578,
 )
 
 _WIFICONFIG = _descriptor.Descriptor(
@@ -1032,10 +1199,17 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='mtk_config', full_name='chromiumos.config.api.software.WifiConfig.mtk_config', index=3,
+      number=4, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
-  nested_types=[_WIFICONFIG_ATH10KCONFIG, _WIFICONFIG_RTW88CONFIG, _WIFICONFIG_INTELCONFIG, ],
+  nested_types=[_WIFICONFIG_ATH10KCONFIG, _WIFICONFIG_RTW88CONFIG, _WIFICONFIG_INTELCONFIG, _WIFICONFIG_MTKCONFIG, ],
   enum_types=[
   ],
   serialized_options=None,
@@ -1048,7 +1222,7 @@
       index=0, containing_type=None, fields=[]),
   ],
   serialized_start=85,
-  serialized_end=4764,
+  serialized_end=5593,
 )
 
 _WIFICONFIG_ATH10KCONFIG_TRANSMITPOWERCHAIN.containing_type = _WIFICONFIG_ATH10KCONFIG
@@ -1090,9 +1264,18 @@
 _WIFICONFIG_INTELCONFIG.fields_by_name['wtas_table'].message_type = _WIFICONFIG_INTELCONFIG_AVERAGE
 _WIFICONFIG_INTELCONFIG.fields_by_name['dsm'].message_type = _WIFICONFIG_INTELCONFIG_DSM
 _WIFICONFIG_INTELCONFIG.containing_type = _WIFICONFIG
+_WIFICONFIG_MTKCONFIG_TRANSMITPOWERCHAIN.containing_type = _WIFICONFIG_MTKCONFIG
+_WIFICONFIG_MTKCONFIG_GEOTRANSMITPOWERCHAIN.containing_type = _WIFICONFIG_MTKCONFIG
+_WIFICONFIG_MTKCONFIG.fields_by_name['tablet_mode_power_table'].message_type = _WIFICONFIG_MTKCONFIG_TRANSMITPOWERCHAIN
+_WIFICONFIG_MTKCONFIG.fields_by_name['non_tablet_mode_power_table'].message_type = _WIFICONFIG_MTKCONFIG_TRANSMITPOWERCHAIN
+_WIFICONFIG_MTKCONFIG.fields_by_name['fcc_power_table'].message_type = _WIFICONFIG_MTKCONFIG_GEOTRANSMITPOWERCHAIN
+_WIFICONFIG_MTKCONFIG.fields_by_name['eu_power_table'].message_type = _WIFICONFIG_MTKCONFIG_GEOTRANSMITPOWERCHAIN
+_WIFICONFIG_MTKCONFIG.fields_by_name['other_power_table'].message_type = _WIFICONFIG_MTKCONFIG_GEOTRANSMITPOWERCHAIN
+_WIFICONFIG_MTKCONFIG.containing_type = _WIFICONFIG
 _WIFICONFIG.fields_by_name['ath10k_config'].message_type = _WIFICONFIG_ATH10KCONFIG
 _WIFICONFIG.fields_by_name['rtw88_config'].message_type = _WIFICONFIG_RTW88CONFIG
 _WIFICONFIG.fields_by_name['intel_config'].message_type = _WIFICONFIG_INTELCONFIG
+_WIFICONFIG.fields_by_name['mtk_config'].message_type = _WIFICONFIG_MTKCONFIG
 _WIFICONFIG.oneofs_by_name['wifi_config'].fields.append(
   _WIFICONFIG.fields_by_name['ath10k_config'])
 _WIFICONFIG.fields_by_name['ath10k_config'].containing_oneof = _WIFICONFIG.oneofs_by_name['wifi_config']
@@ -1102,6 +1285,9 @@
 _WIFICONFIG.oneofs_by_name['wifi_config'].fields.append(
   _WIFICONFIG.fields_by_name['intel_config'])
 _WIFICONFIG.fields_by_name['intel_config'].containing_oneof = _WIFICONFIG.oneofs_by_name['wifi_config']
+_WIFICONFIG.oneofs_by_name['wifi_config'].fields.append(
+  _WIFICONFIG.fields_by_name['mtk_config'])
+_WIFICONFIG.fields_by_name['mtk_config'].containing_oneof = _WIFICONFIG.oneofs_by_name['wifi_config']
 DESCRIPTOR.message_types_by_name['WifiConfig'] = _WIFICONFIG
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
@@ -1204,6 +1390,27 @@
     # @@protoc_insertion_point(class_scope:chromiumos.config.api.software.WifiConfig.IntelConfig)
     })
   ,
+
+  'MtkConfig' : _reflection.GeneratedProtocolMessageType('MtkConfig', (_message.Message,), {
+
+    'TransmitPowerChain' : _reflection.GeneratedProtocolMessageType('TransmitPowerChain', (_message.Message,), {
+      'DESCRIPTOR' : _WIFICONFIG_MTKCONFIG_TRANSMITPOWERCHAIN,
+      '__module__' : 'chromiumos.config.api.software.wifi_config_pb2'
+      # @@protoc_insertion_point(class_scope:chromiumos.config.api.software.WifiConfig.MtkConfig.TransmitPowerChain)
+      })
+    ,
+
+    'GeoTransmitPowerChain' : _reflection.GeneratedProtocolMessageType('GeoTransmitPowerChain', (_message.Message,), {
+      'DESCRIPTOR' : _WIFICONFIG_MTKCONFIG_GEOTRANSMITPOWERCHAIN,
+      '__module__' : 'chromiumos.config.api.software.wifi_config_pb2'
+      # @@protoc_insertion_point(class_scope:chromiumos.config.api.software.WifiConfig.MtkConfig.GeoTransmitPowerChain)
+      })
+    ,
+    'DESCRIPTOR' : _WIFICONFIG_MTKCONFIG,
+    '__module__' : 'chromiumos.config.api.software.wifi_config_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.config.api.software.WifiConfig.MtkConfig)
+    })
+  ,
   'DESCRIPTOR' : _WIFICONFIG,
   '__module__' : 'chromiumos.config.api.software.wifi_config_pb2'
   # @@protoc_insertion_point(class_scope:chromiumos.config.api.software.WifiConfig)
@@ -1223,6 +1430,9 @@
 _sym_db.RegisterMessage(WifiConfig.IntelConfig.Gains.AntennaGain)
 _sym_db.RegisterMessage(WifiConfig.IntelConfig.Average)
 _sym_db.RegisterMessage(WifiConfig.IntelConfig.DSM)
+_sym_db.RegisterMessage(WifiConfig.MtkConfig)
+_sym_db.RegisterMessage(WifiConfig.MtkConfig.TransmitPowerChain)
+_sym_db.RegisterMessage(WifiConfig.MtkConfig.GeoTransmitPowerChain)
 
 
 DESCRIPTOR._options = None
diff --git a/api/gen_sdk/chromiumos/config/api/topology_pb2.py b/api/gen_sdk/chromiumos/config/api/topology_pb2.py
index e6a750c..baa35be 100644
--- a/api/gen_sdk/chromiumos/config/api/topology_pb2.py
+++ b/api/gen_sdk/chromiumos/config/api/topology_pb2.py
@@ -12,6 +12,7 @@
 
 
 from chromite.api.gen_sdk.chromiumos.config.api import component_pb2 as chromiumos_dot_config_dot_api_dot_component__pb2
+from google.protobuf import wrappers_pb2 as google_dot_protobuf_dot_wrappers__pb2
 
 
 DESCRIPTOR = _descriptor.FileDescriptor(
@@ -19,9 +20,9 @@
   package='chromiumos.config.api',
   syntax='proto3',
   serialized_options=b'Z(go.chromium.org/chromiumos/config/go/api',
-  serialized_pb=b'\n$chromiumos/config/api/topology.proto\x12\x15\x63hromiumos.config.api\x1a%chromiumos/config/api/component.proto\"\xdf\x05\n\x08Topology\x12\n\n\x02id\x18\x01 \x01(\t\x12\x32\n\x04type\x18\x02 \x01(\x0e\x32$.chromiumos.config.api.Topology.Type\x12\x45\n\x0b\x64\x65scription\x18\x03 \x03(\x0b\x32\x30.chromiumos.config.api.Topology.DescriptionEntry\x12\x41\n\x10hardware_feature\x18\x04 \x01(\x0b\x32\'.chromiumos.config.api.HardwareFeatures\x1a\x32\n\x10\x44\x65scriptionEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xd4\x03\n\x04Type\x12\x10\n\x0cTYPE_UNKNOWN\x10\x00\x12\n\n\x06SCREEN\x10\x01\x12\x0f\n\x0b\x46ORM_FACTOR\x10\x02\x12\t\n\x05\x41UDIO\x10\x03\x12\n\n\x06STYLUS\x10\x04\x12\x0c\n\x08KEYBOARD\x10\x05\x12\x0b\n\x07THERMAL\x10\x06\x12\n\n\x06\x43\x41MERA\x10\x07\x12(\n$ACCELEROMETER_GYROSCOPE_MAGNETOMETER\x10\x08\x12\x0f\n\x0b\x46INGERPRINT\x10\t\x12\x14\n\x10PROXIMITY_SENSOR\x10\n\x12\x12\n\x0e\x44\x41UGHTER_BOARD\x10\x0b\x12\x18\n\x14NON_VOLATILE_STORAGE\x10\x0c\x12\x07\n\x03RAM\x10\r\x12\x08\n\x04WIFI\x10\x0e\x12\r\n\tLTE_BOARD\x10\x0f\x12\r\n\tSD_READER\x10\x10\x12\x13\n\x0fMOTHERBOARD_USB\x10\x11\x12\r\n\tBLUETOOTH\x10\x12\x12\x0e\n\nBARRELJACK\x10\x13\x12\x10\n\x0cPOWER_BUTTON\x10\x14\x12\x11\n\rVOLUME_BUTTON\x10\x15\x12\x06\n\x02\x45\x43\x10\x16\x12\t\n\x05TOUCH\x10\x17\x12\x07\n\x03TPM\x10\x18\x12\x1a\n\x16MICROPHONE_MUTE_SWITCH\x10\x19\x12\x0b\n\x07\x42\x41TTERY\x10\x1a\x12\x08\n\x04HDMI\x10\x1b\x12\x07\n\x03SOC\x10\x1c\"\xa8\x01\n\x08\x44uration\x12\x32\n\x04type\x18\x01 \x01(\x0e\x32$.chromiumos.config.api.Duration.Type\x12\r\n\x05value\x18\x02 \x01(\x05\"Y\n\x04Type\x12\x10\n\x0cTYPE_UNKNOWN\x10\x00\x12\x10\n\x0cMILLISECONDS\x10\x01\x12\x0b\n\x07SECONDS\x10\x02\x12\x0b\n\x07MINUTES\x10\x03\x12\t\n\x05HOURS\x10\x04\x12\x08\n\x04\x44\x41YS\x10\x05\"\xe2G\n\x10HardwareFeatures\x12;\n\x05usb_c\x18\x01 \x01(\x0b\x32,.chromiumos.config.api.HardwareFeatures.UsbC\x12;\n\x05usb_a\x18\x02 \x01(\x0b\x32,.chromiumos.config.api.HardwareFeatures.UsbA\x12\x38\n\x03lte\x18\x03 \x01(\x0b\x32+.chromiumos.config.api.HardwareFeatures.Lte\x12:\n\x04hdmi\x18\x04 \x01(\x0b\x32,.chromiumos.config.api.HardwareFeatures.Hdmi\x12P\n\tfw_config\x18\x05 \x01(\x0b\x32=.chromiumos.config.api.HardwareFeatures.FirmwareConfiguration\x12<\n\x05\x61udio\x18\x06 \x01(\x0b\x32-.chromiumos.config.api.HardwareFeatures.Audio\x12>\n\x06\x63\x61mera\x18\x07 \x01(\x0b\x32..chromiumos.config.api.HardwareFeatures.Camera\x12L\n\raccelerometer\x18\x08 \x01(\x0b\x32\x35.chromiumos.config.api.HardwareFeatures.Accelerometer\x12\x44\n\tgyroscope\x18\t \x01(\x0b\x32\x31.chromiumos.config.api.HardwareFeatures.Gyroscope\x12J\n\x0cmagnetometer\x18\n \x01(\x0b\x32\x34.chromiumos.config.api.HardwareFeatures.Magnetometer\x12I\n\x0clight_sensor\x18\x0b \x01(\x0b\x32\x33.chromiumos.config.api.HardwareFeatures.LightSensor\x12>\n\x06screen\x18\x0c \x01(\x0b\x32..chromiumos.config.api.HardwareFeatures.Screen\x12G\n\x0b\x66orm_factor\x18\r \x01(\x0b\x32\x32.chromiumos.config.api.HardwareFeatures.FormFactor\x12>\n\x06stylus\x18\x0e \x01(\x0b\x32..chromiumos.config.api.HardwareFeatures.Stylus\x12\x42\n\x08keyboard\x18\x0f \x01(\x0b\x32\x30.chromiumos.config.api.HardwareFeatures.Keyboard\x12>\n\x06memory\x18\x10 \x01(\x0b\x32..chromiumos.config.api.HardwareFeatures.Memory\x12H\n\x0b\x66ingerprint\x18\x11 \x01(\x0b\x32\x33.chromiumos.config.api.HardwareFeatures.Fingerprint\x12@\n\x07storage\x18\x12 \x01(\x0b\x32/.chromiumos.config.api.HardwareFeatures.Storage\x12\x44\n\tbluetooth\x18\x13 \x01(\x0b\x32\x31.chromiumos.config.api.HardwareFeatures.Bluetooth\x12\x46\n\nbarreljack\x18\x14 \x01(\x0b\x32\x32.chromiumos.config.api.HardwareFeatures.BarrelJack\x12:\n\x04wifi\x18\x17 \x01(\x0b\x32,.chromiumos.config.api.HardwareFeatures.Wifi\x12\x44\n\x0cpower_button\x18\x15 \x01(\x0b\x32..chromiumos.config.api.HardwareFeatures.Button\x12\x45\n\rvolume_button\x18\x16 \x01(\x0b\x32..chromiumos.config.api.HardwareFeatures.Button\x12W\n\x13\x65mbedded_controller\x18\x18 \x01(\x0b\x32:.chromiumos.config.api.HardwareFeatures.EmbeddedController\x12^\n\x17trusted_platform_module\x18\x19 \x01(\x0b\x32=.chromiumos.config.api.HardwareFeatures.TrustedPlatformModule\x12\x46\n\nhotwording\x18\x1a \x01(\x0b\x32\x32.chromiumos.config.api.HardwareFeatures.Hotwording\x12@\n\x07\x64isplay\x18\x1b \x01(\x0b\x32/.chromiumos.config.api.HardwareFeatures.Display\x12\x42\n\x08touchpad\x18\x1c \x01(\x0b\x32\x30.chromiumos.config.api.HardwareFeatures.Touchpad\x12\\\n\x16microphone_mute_switch\x18\x1d \x01(\x0b\x32<.chromiumos.config.api.HardwareFeatures.MicrophoneMuteSwitch\x12@\n\x07\x62\x61ttery\x18\x1e \x01(\x0b\x32/.chromiumos.config.api.HardwareFeatures.Battery\x12M\n\x0eprivacy_screen\x18\x1f \x01(\x0b\x32\x35.chromiumos.config.api.HardwareFeatures.PrivacyScreen\x12\x38\n\x03soc\x18  \x01(\x0b\x32+.chromiumos.config.api.HardwareFeatures.Soc\x12R\n\x0c\x64p_converter\x18! \x01(\x0b\x32<.chromiumos.config.api.HardwareFeatures.DisplayPortConverter\x1a\x16\n\x05\x43ount\x12\r\n\x05value\x18\x01 \x01(\r\x1a\x44\n\x04UsbC\x12<\n\x05\x63ount\x18\x01 \x01(\x0b\x32-.chromiumos.config.api.HardwareFeatures.Count\x1a\x44\n\x04UsbA\x12<\n\x05\x63ount\x18\x01 \x01(\x0b\x32-.chromiumos.config.api.HardwareFeatures.Count\x1aV\n\x03Lte\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12\r\n\x05model\x18\x02 \x01(\t\x1aH\n\x04Hdmi\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\x34\n\x15\x46irmwareConfiguration\x12\r\n\x05value\x18\x01 \x01(\r\x12\x0c\n\x04mask\x18\x02 \x01(\r\x1a\x89\x06\n\x05\x41udio\x12M\n\x0b\x61udio_codec\x18\x01 \x01(\x0e\x32\x38.chromiumos.config.api.HardwareFeatures.Audio.AudioCodec\x12L\n\x0bspeaker_amp\x18\x02 \x01(\x0e\x32\x37.chromiumos.config.api.HardwareFeatures.Audio.Amplifier\x12Q\n\x0fheadphone_codec\x18\x03 \x01(\x0e\x32\x38.chromiumos.config.api.HardwareFeatures.Audio.AudioCodec\x12\x45\n\x0elid_microphone\x18\x04 \x01(\x0b\x32-.chromiumos.config.api.HardwareFeatures.Count\x12\x46\n\x0f\x62\x61se_microphone\x18\x05 \x01(\x0b\x32-.chromiumos.config.api.HardwareFeatures.Count\x12\x45\n\x11speaker_amplifier\x18\x06 \x01(\x0b\x32*.chromiumos.config.api.Component.Amplifier\"\x9d\x01\n\nAudioCodec\x12\x17\n\x13\x41UDIO_CODEC_UNKNOWN\x10\x00\x12\n\n\x06RT5682\x10\x01\x12\x0c\n\x08\x41LC5682I\x10\x02\x12\x0b\n\x07\x41LC5682\x10\x03\x12\n\n\x06\x44\x41\x37\x32\x31\x39\x10\x08\x12\r\n\tNAU88L25B\x10\n\x12\x0b\n\x07\x43S42L42\x10\x0b\x12\x0e\n\nALC5682IVS\x10\x0c\x12\x0b\n\x07WCD9385\x10\r\"\x04\x08\x04\x10\x07\"\x04\x08\t\x10\t\"\x99\x01\n\tAmplifier\x12\x15\n\x11\x41MPLIFIER_UNKNOWN\x10\x00\x12\x0c\n\x08MAX98357\x10\x04\x12\x0c\n\x08MAX98373\x10\x05\x12\x0c\n\x08MAX98360\x10\x06\x12\n\n\x06RT1015\x10\x07\x12\x0b\n\x07\x41LC1011\x10\t\x12\x0b\n\x07RT1015P\x10\n\x12\x0b\n\x07\x41LC1019\x10\x0b\x12\x0c\n\x08MAX98390\x10\x0c\"\x04\x08\x01\x10\x03\"\x04\x08\x08\x10\x08\x1a\xf9\x05\n\x06\x43\x61mera\x12\x46\n\x07\x64\x65vices\x18\x04 \x03(\x0b\x32\x35.chromiumos.config.api.HardwareFeatures.Camera.Device\x1a\xd2\x02\n\x06\x44\x65vice\x12K\n\tinterface\x18\x02 \x01(\x0e\x32\x38.chromiumos.config.api.HardwareFeatures.Camera.Interface\x12\x45\n\x06\x66\x61\x63ing\x18\x03 \x01(\x0e\x32\x35.chromiumos.config.api.HardwareFeatures.Camera.Facing\x12O\n\x0borientation\x18\x04 \x01(\x0e\x32:.chromiumos.config.api.HardwareFeatures.Camera.Orientation\x12\r\n\x05\x66lags\x18\x05 \x01(\r\x12\x0b\n\x03ids\x18\x06 \x03(\t\x12G\n\x0eprivacy_switch\x18\x07 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\"I\n\tInterface\x12\x15\n\x11INTERFACE_UNKNOWN\x10\x00\x12\x11\n\rINTERFACE_USB\x10\x01\x12\x12\n\x0eINTERFACE_MIPI\x10\x02\"?\n\x06\x46\x61\x63ing\x12\x12\n\x0e\x46\x41\x43ING_UNKNOWN\x10\x00\x12\x10\n\x0c\x46\x41\x43ING_FRONT\x10\x01\x12\x0f\n\x0b\x46\x41\x43ING_BACK\x10\x02\"w\n\x0bOrientation\x12\x17\n\x13ORIENTATION_UNKNOWN\x10\x00\x12\x11\n\rORIENTATION_0\x10\x01\x12\x12\n\x0eORIENTATION_90\x10\x02\x12\x13\n\x0fORIENTATION_180\x10\x03\x12\x13\n\x0fORIENTATION_270\x10\x04\"M\n\x05\x46lags\x12\x0e\n\nFLAGS_NONE\x10\x00\x12\x17\n\x13\x46LAGS_SUPPORT_1080P\x10\x01\x12\x1b\n\x17\x46LAGS_SUPPORT_AUTOFOCUS\x10\x02\x1a\xa8\x01\n\rAccelerometer\x12J\n\x11lid_accelerometer\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12K\n\x12\x62\x61se_accelerometer\x18\x02 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\x9c\x01\n\tGyroscope\x12\x46\n\rlid_gyroscope\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12G\n\x0e\x62\x61se_gyroscope\x18\x02 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\xa5\x01\n\x0cMagnetometer\x12I\n\x10lid_magnetometer\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12J\n\x11\x62\x61se_magnetometer\x18\x02 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\xa2\x01\n\x0bLightSensor\x12H\n\x0flid_lightsensor\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12I\n\x10\x62\x61se_lightsensor\x18\x02 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\xaa\x01\n\x06Screen\x12R\n\x10panel_properties\x18\x03 \x01(\x0b\x32\x38.chromiumos.config.api.Component.DisplayPanel.Properties\x12\x46\n\rtouch_support\x18\x02 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.PresentJ\x04\x08\x01\x10\x02\x1a\xff\x01\n\nFormFactor\x12V\n\x0b\x66orm_factor\x18\x01 \x01(\x0e\x32\x41.chromiumos.config.api.HardwareFeatures.FormFactor.FormFactorType\"\x98\x01\n\x0e\x46ormFactorType\x12\x17\n\x13\x46ORM_FACTOR_UNKNOWN\x10\x00\x12\r\n\tCLAMSHELL\x10\x01\x12\x0f\n\x0b\x43ONVERTIBLE\x10\x02\x12\x0e\n\nDETACHABLE\x10\x03\x12\x0e\n\nCHROMEBASE\x10\x04\x12\r\n\tCHROMEBOX\x10\x05\x12\r\n\tCHROMEBIT\x10\x06\x12\x0f\n\x0b\x43HROMESLATE\x10\x07\x1a\x9b\x01\n\x06Stylus\x12I\n\x06stylus\x18\x01 \x01(\x0e\x32\x39.chromiumos.config.api.HardwareFeatures.Stylus.StylusType\"F\n\nStylusType\x12\x12\n\x0eSTYLUS_UNKNOWN\x10\x00\x12\x08\n\x04NONE\x10\x01\x12\x0c\n\x08INTERNAL\x10\x02\x12\x0c\n\x08\x45XTERNAL\x10\x03\x1a\x84\x03\n\x08Keyboard\x12T\n\rkeyboard_type\x18\x01 \x01(\x0e\x32=.chromiumos.config.api.HardwareFeatures.Keyboard.KeyboardType\x12\x42\n\tbacklight\x18\x02 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12\x45\n\x0cpower_button\x18\x03 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12\x44\n\x0bnumeric_pad\x18\x04 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\"Q\n\x0cKeyboardType\x12\x19\n\x15KEYBOARD_TYPE_UNKNOWN\x10\x00\x12\x0c\n\x08INTERNAL\x10\x01\x12\x08\n\x04NONE\x10\x02\x12\x0e\n\nDETACHABLE\x10\x03\x1aJ\n\x06Memory\x12@\n\x07profile\x18\x01 \x01(\x0b\x32/.chromiumos.config.api.Component.Memory.Profile\x1a\xc8\x02\n\x0b\x46ingerprint\x12N\n\x08location\x18\x01 \x01(\x0e\x32<.chromiumos.config.api.HardwareFeatures.Fingerprint.Location\x12\r\n\x05\x62oard\x18\x02 \x01(\t\x12\x12\n\nro_version\x18\x03 \x01(\t\"\xc5\x01\n\x08Location\x12\x14\n\x10LOCATION_UNKNOWN\x10\x00\x12\x19\n\x15POWER_BUTTON_TOP_LEFT\x10\x01\x12\x18\n\x14KEYBOARD_BOTTOM_LEFT\x10\x02\x12\x19\n\x15KEYBOARD_BOTTOM_RIGHT\x10\x03\x12\x16\n\x12KEYBOARD_TOP_RIGHT\x10\x04\x12\x0f\n\x0bNOT_PRESENT\x10\x05\x12\x0e\n\nRIGHT_SIDE\x10\x06\x12\r\n\tLEFT_SIDE\x10\x07\x12\x0b\n\x07PRESENT\x10\x08\x1a\x66\n\x07Storage\x12J\n\x0cstorage_type\x18\x01 \x01(\x0e\x32\x34.chromiumos.config.api.Component.Storage.StorageType\x12\x0f\n\x07size_gb\x18\x02 \x01(\r\x1a\x8c\x01\n\tBluetooth\x12=\n\tcomponent\x18\x01 \x01(\x0b\x32*.chromiumos.config.api.Component.Bluetooth\x12@\n\x07present\x18\x02 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1aN\n\nBarrelJack\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\xf7\x01\n\x04Wifi\x12T\n\x18supported_wlan_protocols\x18\x01 \x03(\x0e\x32\x32.chromiumos.config.api.Component.Wifi.WLANProtocol\x12I\n\nwifi_chips\x18\x02 \x03(\x0e\x32\x35.chromiumos.config.api.HardwareFeatures.Wifi.WifiChip\"N\n\x08WifiChip\x12\x15\n\x11WIFI_CHIP_UNKNOWN\x10\x00\x12\x15\n\x11WIRELESS_86ED801D\x10\x01\x12\x14\n\x10WIRELESS_REALTEK\x10\x02\x1a\xa0\x02\n\x06\x42utton\x12\x45\n\x06region\x18\x01 \x01(\x0e\x32\x35.chromiumos.config.api.HardwareFeatures.Button.Region\x12\x41\n\x04\x65\x64ge\x18\x02 \x01(\x0e\x32\x33.chromiumos.config.api.HardwareFeatures.Button.Edge\x12\x10\n\x08position\x18\x03 \x01(\x02\"6\n\x06Region\x12\x12\n\x0eREGION_UNKNOWN\x10\x00\x12\n\n\x06SCREEN\x10\x01\x12\x0c\n\x08KEYBOARD\x10\x02\"B\n\x04\x45\x64ge\x12\x10\n\x0c\x45\x44GE_UNKNOWN\x10\x00\x12\x08\n\x04LEFT\x10\x01\x12\t\n\x05RIGHT\x10\x02\x12\x07\n\x03TOP\x10\x03\x12\n\n\x06\x42OTTOM\x10\x04\x1a\xc9\x02\n\x12\x45mbeddedController\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12\x62\n\x07\x65\x63_type\x18\x02 \x01(\x0e\x32Q.chromiumos.config.api.HardwareFeatures.EmbeddedController.EmbeddedControllerType\x12\x41\n\x04part\x18\x03 \x01(\x0b\x32\x33.chromiumos.config.api.Component.EmbeddedController\"J\n\x16\x45mbeddedControllerType\x12\x13\n\x0f\x45\x43_TYPE_UNKNOWN\x10\x00\x12\r\n\tEC_CHROME\x10\x01\x12\x0c\n\x08\x45\x43_WILCO\x10\x02\x1a\xe0\x01\n\x15TrustedPlatformModule\x12i\n\x08tpm_type\x18\x01 \x01(\x0e\x32W.chromiumos.config.api.HardwareFeatures.TrustedPlatformModule.TrustedPlatformModuleType\"\\\n\x19TrustedPlatformModuleType\x12\x14\n\x10TPM_TYPE_UNKNOWN\x10\x00\x12\x0f\n\x0bTHIRD_PARTY\x10\x01\x12\x0b\n\x07GSC_H1B\x10\x02\x12\x0b\n\x07GSC_H1D\x10\x03\x1aN\n\nHotwording\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\xa9\x01\n\x07\x44isplay\x12\x42\n\x04type\x18\x01 \x01(\x0e\x32\x34.chromiumos.config.api.HardwareFeatures.Display.Type\"Z\n\x04Type\x12\x10\n\x0cTYPE_UNKNOWN\x10\x00\x12\x11\n\rTYPE_INTERNAL\x10\x01\x12\x11\n\rTYPE_EXTERNAL\x10\x02\x12\x1a\n\x16TYPE_INTERNAL_EXTERNAL\x10\x03\x1aL\n\x08Touchpad\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1aX\n\x14MicrophoneMuteSwitch\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\xb6\x05\n\x07\x42\x61ttery\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12J\n\x08lifetime\x18\x02 \x01(\x0b\x32\x38.chromiumos.config.api.HardwareFeatures.Battery.Lifetime\x12J\n\x08\x63harging\x18\x03 \x01(\x0b\x32\x38.chromiumos.config.api.HardwareFeatures.Battery.Charging\x1a\x9f\x02\n\x08Lifetime\x12\x35\n\x0cshipping_min\x18\x01 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x12\x37\n\x0e\x64\x65\x65p_sleep_min\x18\x02 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x12\x34\n\x0bsuspend_min\x18\x03 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x12\x38\n\x0flucid_sleep_min\x18\x04 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x12\x33\n\nactive_min\x18\x05 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x1a\xae\x01\n\x08\x43harging\x12\x33\n\nactive_max\x18\x01 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x12\x34\n\x0bsuspend_max\x18\x02 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x12\x37\n\x0e\x64\x65\x65p_sleep_max\x18\x03 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x1aQ\n\rPrivacyScreen\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\x45\n\x03Soc\x12>\n\x08\x66\x65\x61tures\x18\x01 \x03(\x0e\x32,.chromiumos.config.api.Component.Soc.Feature\x1a\x61\n\x14\x44isplayPortConverter\x12I\n\nconverters\x18\x01 \x03(\x0b\x32\x35.chromiumos.config.api.Component.DisplayPortConverter\"<\n\x07Present\x12\x13\n\x0fPRESENT_UNKNOWN\x10\x00\x12\x0b\n\x07PRESENT\x10\x01\x12\x0f\n\x0bNOT_PRESENT\x10\x02\x42*Z(go.chromium.org/chromiumos/config/go/apib\x06proto3'
+  serialized_pb=b'\n$chromiumos/config/api/topology.proto\x12\x15\x63hromiumos.config.api\x1a%chromiumos/config/api/component.proto\x1a\x1egoogle/protobuf/wrappers.proto\"\x9a\x06\n\x08Topology\x12\n\n\x02id\x18\x01 \x01(\t\x12\x32\n\x04type\x18\x02 \x01(\x0e\x32$.chromiumos.config.api.Topology.Type\x12\x45\n\x0b\x64\x65scription\x18\x03 \x03(\x0b\x32\x30.chromiumos.config.api.Topology.DescriptionEntry\x12\x41\n\x10hardware_feature\x18\x04 \x01(\x0b\x32\'.chromiumos.config.api.HardwareFeatures\x1a\x32\n\x10\x44\x65scriptionEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x8f\x04\n\x04Type\x12\x10\n\x0cTYPE_UNKNOWN\x10\x00\x12\n\n\x06SCREEN\x10\x01\x12\x0f\n\x0b\x46ORM_FACTOR\x10\x02\x12\t\n\x05\x41UDIO\x10\x03\x12\n\n\x06STYLUS\x10\x04\x12\x0c\n\x08KEYBOARD\x10\x05\x12\x0b\n\x07THERMAL\x10\x06\x12\n\n\x06\x43\x41MERA\x10\x07\x12(\n$ACCELEROMETER_GYROSCOPE_MAGNETOMETER\x10\x08\x12\x0f\n\x0b\x46INGERPRINT\x10\t\x12\x14\n\x10PROXIMITY_SENSOR\x10\n\x12\x12\n\x0e\x44\x41UGHTER_BOARD\x10\x0b\x12\x18\n\x14NON_VOLATILE_STORAGE\x10\x0c\x12\x07\n\x03RAM\x10\r\x12\x08\n\x04WIFI\x10\x0e\x12\x12\n\x0e\x43\x45LLULAR_BOARD\x10\x0f\x12\r\n\tSD_READER\x10\x10\x12\x13\n\x0fMOTHERBOARD_USB\x10\x11\x12\r\n\tBLUETOOTH\x10\x12\x12\x0e\n\nBARRELJACK\x10\x13\x12\x10\n\x0cPOWER_BUTTON\x10\x14\x12\x11\n\rVOLUME_BUTTON\x10\x15\x12\x06\n\x02\x45\x43\x10\x16\x12\t\n\x05TOUCH\x10\x17\x12\x07\n\x03TPM\x10\x18\x12\x1a\n\x16MICROPHONE_MUTE_SWITCH\x10\x19\x12\x0b\n\x07\x42\x41TTERY\x10\x1a\x12\x08\n\x04HDMI\x10\x1b\x12\x07\n\x03SOC\x10\x1c\x12\x07\n\x03HPS\x10\x1d\x12\x10\n\x0c\x44P_CONVERTER\x10\x1e\x12\x07\n\x03POE\x10\x1f\x12\x10\n\x0cPOWER_SUPPLY\x10 \"\xa8\x01\n\x08\x44uration\x12\x32\n\x04type\x18\x01 \x01(\x0e\x32$.chromiumos.config.api.Duration.Type\x12\r\n\x05value\x18\x02 \x01(\x05\"Y\n\x04Type\x12\x10\n\x0cTYPE_UNKNOWN\x10\x00\x12\x10\n\x0cMILLISECONDS\x10\x01\x12\x0b\n\x07SECONDS\x10\x02\x12\x0b\n\x07MINUTES\x10\x03\x12\t\n\x05HOURS\x10\x04\x12\x08\n\x04\x44\x41YS\x10\x05\"\xeaR\n\x10HardwareFeatures\x12;\n\x05usb_c\x18\x01 \x01(\x0b\x32,.chromiumos.config.api.HardwareFeatures.UsbC\x12;\n\x05usb_a\x18\x02 \x01(\x0b\x32,.chromiumos.config.api.HardwareFeatures.UsbA\x12\x42\n\x08\x63\x65llular\x18\x03 \x01(\x0b\x32\x30.chromiumos.config.api.HardwareFeatures.Cellular\x12:\n\x04hdmi\x18\x04 \x01(\x0b\x32,.chromiumos.config.api.HardwareFeatures.Hdmi\x12P\n\tfw_config\x18\x05 \x01(\x0b\x32=.chromiumos.config.api.HardwareFeatures.FirmwareConfiguration\x12<\n\x05\x61udio\x18\x06 \x01(\x0b\x32-.chromiumos.config.api.HardwareFeatures.Audio\x12>\n\x06\x63\x61mera\x18\x07 \x01(\x0b\x32..chromiumos.config.api.HardwareFeatures.Camera\x12L\n\raccelerometer\x18\x08 \x01(\x0b\x32\x35.chromiumos.config.api.HardwareFeatures.Accelerometer\x12\x44\n\tgyroscope\x18\t \x01(\x0b\x32\x31.chromiumos.config.api.HardwareFeatures.Gyroscope\x12J\n\x0cmagnetometer\x18\n \x01(\x0b\x32\x34.chromiumos.config.api.HardwareFeatures.Magnetometer\x12I\n\x0clight_sensor\x18\x0b \x01(\x0b\x32\x33.chromiumos.config.api.HardwareFeatures.LightSensor\x12>\n\x06screen\x18\x0c \x01(\x0b\x32..chromiumos.config.api.HardwareFeatures.Screen\x12G\n\x0b\x66orm_factor\x18\r \x01(\x0b\x32\x32.chromiumos.config.api.HardwareFeatures.FormFactor\x12>\n\x06stylus\x18\x0e \x01(\x0b\x32..chromiumos.config.api.HardwareFeatures.Stylus\x12\x42\n\x08keyboard\x18\x0f \x01(\x0b\x32\x30.chromiumos.config.api.HardwareFeatures.Keyboard\x12>\n\x06memory\x18\x10 \x01(\x0b\x32..chromiumos.config.api.HardwareFeatures.Memory\x12H\n\x0b\x66ingerprint\x18\x11 \x01(\x0b\x32\x33.chromiumos.config.api.HardwareFeatures.Fingerprint\x12@\n\x07storage\x18\x12 \x01(\x0b\x32/.chromiumos.config.api.HardwareFeatures.Storage\x12\x44\n\tbluetooth\x18\x13 \x01(\x0b\x32\x31.chromiumos.config.api.HardwareFeatures.Bluetooth\x12\x46\n\nbarreljack\x18\x14 \x01(\x0b\x32\x32.chromiumos.config.api.HardwareFeatures.BarrelJack\x12:\n\x04wifi\x18\x17 \x01(\x0b\x32,.chromiumos.config.api.HardwareFeatures.Wifi\x12\x44\n\x0cpower_button\x18\x15 \x01(\x0b\x32..chromiumos.config.api.HardwareFeatures.Button\x12\x45\n\rvolume_button\x18\x16 \x01(\x0b\x32..chromiumos.config.api.HardwareFeatures.Button\x12W\n\x13\x65mbedded_controller\x18\x18 \x01(\x0b\x32:.chromiumos.config.api.HardwareFeatures.EmbeddedController\x12^\n\x17trusted_platform_module\x18\x19 \x01(\x0b\x32=.chromiumos.config.api.HardwareFeatures.TrustedPlatformModule\x12\x46\n\nhotwording\x18\x1a \x01(\x0b\x32\x32.chromiumos.config.api.HardwareFeatures.Hotwording\x12@\n\x07\x64isplay\x18\x1b \x01(\x0b\x32/.chromiumos.config.api.HardwareFeatures.Display\x12\x42\n\x08touchpad\x18\x1c \x01(\x0b\x32\x30.chromiumos.config.api.HardwareFeatures.Touchpad\x12\\\n\x16microphone_mute_switch\x18\x1d \x01(\x0b\x32<.chromiumos.config.api.HardwareFeatures.MicrophoneMuteSwitch\x12@\n\x07\x62\x61ttery\x18\x1e \x01(\x0b\x32/.chromiumos.config.api.HardwareFeatures.Battery\x12M\n\x0eprivacy_screen\x18\x1f \x01(\x0b\x32\x35.chromiumos.config.api.HardwareFeatures.PrivacyScreen\x12\x38\n\x03soc\x18  \x01(\x0b\x32+.chromiumos.config.api.HardwareFeatures.Soc\x12R\n\x0c\x64p_converter\x18! \x01(\x0b\x32<.chromiumos.config.api.HardwareFeatures.DisplayPortConverter\x12\x38\n\x03hps\x18\" \x01(\x0b\x32+.chromiumos.config.api.HardwareFeatures.Hps\x12\x38\n\x03poe\x18# \x01(\x0b\x32+.chromiumos.config.api.HardwareFeatures.PoE\x12I\n\x0cpower_supply\x18$ \x01(\x0b\x32\x33.chromiumos.config.api.HardwareFeatures.PowerSupply\x1a\x16\n\x05\x43ount\x12\r\n\x05value\x18\x01 \x01(\r\x1a\x44\n\x04UsbC\x12<\n\x05\x63ount\x18\x01 \x01(\x0b\x32-.chromiumos.config.api.HardwareFeatures.Count\x1a\x44\n\x04UsbA\x12<\n\x05\x63ount\x18\x01 \x01(\x0b\x32-.chromiumos.config.api.HardwareFeatures.Count\x1a\x89\x02\n\x08\x43\x65llular\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12\r\n\x05model\x18\x02 \x01(\t\x12K\n\x04type\x18\x03 \x01(\x0e\x32=.chromiumos.config.api.HardwareFeatures.Cellular.CellularType\x12\x1b\n\x13\x61ttach_apn_required\x18\x04 \x01(\x08\"B\n\x0c\x43\x65llularType\x12\x0f\n\x0bNOT_PRESENT\x10\x00\x12\x10\n\x0c\x43\x45LLULAR_LTE\x10\x01\x12\x0f\n\x0b\x43\x45LLULAR_5G\x10\x02\x1aH\n\x04Hdmi\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\x34\n\x15\x46irmwareConfiguration\x12\r\n\x05value\x18\x01 \x01(\r\x12\x0c\n\x04mask\x18\x02 \x01(\r\x1a\xec\n\n\x05\x41udio\x12M\n\x0b\x61udio_codec\x18\x01 \x01(\x0e\x32\x38.chromiumos.config.api.HardwareFeatures.Audio.AudioCodec\x12L\n\x0bspeaker_amp\x18\x02 \x01(\x0e\x32\x37.chromiumos.config.api.HardwareFeatures.Audio.Amplifier\x12Q\n\x0fheadphone_codec\x18\x03 \x01(\x0e\x32\x38.chromiumos.config.api.HardwareFeatures.Audio.AudioCodec\x12\x45\n\x0elid_microphone\x18\x04 \x01(\x0b\x32-.chromiumos.config.api.HardwareFeatures.Count\x12\x46\n\x0f\x62\x61se_microphone\x18\x05 \x01(\x0b\x32-.chromiumos.config.api.HardwareFeatures.Count\x12\x45\n\x11speaker_amplifier\x18\x06 \x01(\x0b\x32*.chromiumos.config.api.Component.Amplifier\x12N\n\x0c\x63\x61rd_configs\x18\x07 \x03(\x0b\x32\x38.chromiumos.config.api.HardwareFeatures.Audio.CardConfig\x12W\n\x0b\x63ras_config\x18\x08 \x01(\x0e\x32\x42.chromiumos.config.api.HardwareFeatures.Audio.AudioConfigStructure\x1a\xe6\x02\n\nCardConfig\x12\x11\n\tcard_name\x18\x01 \x01(\t\x12\x30\n\nucm_suffix\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12V\n\nucm_config\x18\x03 \x01(\x0e\x32\x42.chromiumos.config.api.HardwareFeatures.Audio.AudioConfigStructure\x12W\n\x0b\x63ras_config\x18\x04 \x01(\x0e\x32\x42.chromiumos.config.api.HardwareFeatures.Audio.AudioConfigStructure\x12\x62\n\x16sound_card_init_config\x18\x05 \x01(\x0e\x32\x42.chromiumos.config.api.HardwareFeatures.Audio.AudioConfigStructure\"\x9d\x01\n\nAudioCodec\x12\x17\n\x13\x41UDIO_CODEC_UNKNOWN\x10\x00\x12\n\n\x06RT5682\x10\x01\x12\x0c\n\x08\x41LC5682I\x10\x02\x12\x0b\n\x07\x41LC5682\x10\x03\x12\n\n\x06\x44\x41\x37\x32\x31\x39\x10\x08\x12\r\n\tNAU88L25B\x10\n\x12\x0b\n\x07\x43S42L42\x10\x0b\x12\x0e\n\nALC5682IVS\x10\x0c\x12\x0b\n\x07WCD9385\x10\r\"\x04\x08\x04\x10\x07\"\x04\x08\t\x10\t\"\x99\x01\n\tAmplifier\x12\x15\n\x11\x41MPLIFIER_UNKNOWN\x10\x00\x12\x0c\n\x08MAX98357\x10\x04\x12\x0c\n\x08MAX98373\x10\x05\x12\x0c\n\x08MAX98360\x10\x06\x12\n\n\x06RT1015\x10\x07\x12\x0b\n\x07\x41LC1011\x10\t\x12\x0b\n\x07RT1015P\x10\n\x12\x0b\n\x07\x41LC1019\x10\x0b\x12\x0c\n\x08MAX98390\x10\x0c\"\x04\x08\x01\x10\x03\"\x04\x08\x08\x10\x08\"O\n\x14\x41udioConfigStructure\x12\x1f\n\x1b\x41UDIO_CONFIG_STRUCTURE_NONE\x10\x00\x12\n\n\x06\x44\x45SIGN\x10\x01\x12\n\n\x06\x43OMMON\x10\x02\x1a\xf9\x05\n\x06\x43\x61mera\x12\x46\n\x07\x64\x65vices\x18\x04 \x03(\x0b\x32\x35.chromiumos.config.api.HardwareFeatures.Camera.Device\x1a\xd2\x02\n\x06\x44\x65vice\x12K\n\tinterface\x18\x02 \x01(\x0e\x32\x38.chromiumos.config.api.HardwareFeatures.Camera.Interface\x12\x45\n\x06\x66\x61\x63ing\x18\x03 \x01(\x0e\x32\x35.chromiumos.config.api.HardwareFeatures.Camera.Facing\x12O\n\x0borientation\x18\x04 \x01(\x0e\x32:.chromiumos.config.api.HardwareFeatures.Camera.Orientation\x12\r\n\x05\x66lags\x18\x05 \x01(\r\x12\x0b\n\x03ids\x18\x06 \x03(\t\x12G\n\x0eprivacy_switch\x18\x07 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\"I\n\tInterface\x12\x15\n\x11INTERFACE_UNKNOWN\x10\x00\x12\x11\n\rINTERFACE_USB\x10\x01\x12\x12\n\x0eINTERFACE_MIPI\x10\x02\"?\n\x06\x46\x61\x63ing\x12\x12\n\x0e\x46\x41\x43ING_UNKNOWN\x10\x00\x12\x10\n\x0c\x46\x41\x43ING_FRONT\x10\x01\x12\x0f\n\x0b\x46\x41\x43ING_BACK\x10\x02\"w\n\x0bOrientation\x12\x17\n\x13ORIENTATION_UNKNOWN\x10\x00\x12\x11\n\rORIENTATION_0\x10\x01\x12\x12\n\x0eORIENTATION_90\x10\x02\x12\x13\n\x0fORIENTATION_180\x10\x03\x12\x13\n\x0fORIENTATION_270\x10\x04\"M\n\x05\x46lags\x12\x0e\n\nFLAGS_NONE\x10\x00\x12\x17\n\x13\x46LAGS_SUPPORT_1080P\x10\x01\x12\x1b\n\x17\x46LAGS_SUPPORT_AUTOFOCUS\x10\x02\x1a\xa8\x01\n\rAccelerometer\x12J\n\x11lid_accelerometer\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12K\n\x12\x62\x61se_accelerometer\x18\x02 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\x9c\x01\n\tGyroscope\x12\x46\n\rlid_gyroscope\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12G\n\x0e\x62\x61se_gyroscope\x18\x02 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\xa5\x01\n\x0cMagnetometer\x12I\n\x10lid_magnetometer\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12J\n\x11\x62\x61se_magnetometer\x18\x02 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\xa2\x01\n\x0bLightSensor\x12H\n\x0flid_lightsensor\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12I\n\x10\x62\x61se_lightsensor\x18\x02 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\xaa\x01\n\x06Screen\x12R\n\x10panel_properties\x18\x03 \x01(\x0b\x32\x38.chromiumos.config.api.Component.DisplayPanel.Properties\x12\x46\n\rtouch_support\x18\x02 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.PresentJ\x04\x08\x01\x10\x02\x1a\xff\x01\n\nFormFactor\x12V\n\x0b\x66orm_factor\x18\x01 \x01(\x0e\x32\x41.chromiumos.config.api.HardwareFeatures.FormFactor.FormFactorType\"\x98\x01\n\x0e\x46ormFactorType\x12\x17\n\x13\x46ORM_FACTOR_UNKNOWN\x10\x00\x12\r\n\tCLAMSHELL\x10\x01\x12\x0f\n\x0b\x43ONVERTIBLE\x10\x02\x12\x0e\n\nDETACHABLE\x10\x03\x12\x0e\n\nCHROMEBASE\x10\x04\x12\r\n\tCHROMEBOX\x10\x05\x12\r\n\tCHROMEBIT\x10\x06\x12\x0f\n\x0b\x43HROMESLATE\x10\x07\x1a\x9b\x01\n\x06Stylus\x12I\n\x06stylus\x18\x01 \x01(\x0e\x32\x39.chromiumos.config.api.HardwareFeatures.Stylus.StylusType\"F\n\nStylusType\x12\x12\n\x0eSTYLUS_UNKNOWN\x10\x00\x12\x08\n\x04NONE\x10\x01\x12\x0c\n\x08INTERNAL\x10\x02\x12\x0c\n\x08\x45XTERNAL\x10\x03\x1a\xa2\x03\n\x08Keyboard\x12T\n\rkeyboard_type\x18\x01 \x01(\x0e\x32=.chromiumos.config.api.HardwareFeatures.Keyboard.KeyboardType\x12\x42\n\tbacklight\x18\x02 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12\x45\n\x0cpower_button\x18\x03 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12\x44\n\x0bnumeric_pad\x18\x04 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12\x1c\n\x14\x62\x61\x63klight_user_steps\x18\x05 \x03(\x01\"Q\n\x0cKeyboardType\x12\x19\n\x15KEYBOARD_TYPE_UNKNOWN\x10\x00\x12\x0c\n\x08INTERNAL\x10\x01\x12\x08\n\x04NONE\x10\x02\x12\x0e\n\nDETACHABLE\x10\x03\x1aJ\n\x06Memory\x12@\n\x07profile\x18\x01 \x01(\x0b\x32/.chromiumos.config.api.Component.Memory.Profile\x1a\xc8\x02\n\x0b\x46ingerprint\x12N\n\x08location\x18\x01 \x01(\x0e\x32<.chromiumos.config.api.HardwareFeatures.Fingerprint.Location\x12\r\n\x05\x62oard\x18\x02 \x01(\t\x12\x12\n\nro_version\x18\x03 \x01(\t\"\xc5\x01\n\x08Location\x12\x14\n\x10LOCATION_UNKNOWN\x10\x00\x12\x19\n\x15POWER_BUTTON_TOP_LEFT\x10\x01\x12\x18\n\x14KEYBOARD_BOTTOM_LEFT\x10\x02\x12\x19\n\x15KEYBOARD_BOTTOM_RIGHT\x10\x03\x12\x16\n\x12KEYBOARD_TOP_RIGHT\x10\x04\x12\x0f\n\x0bNOT_PRESENT\x10\x05\x12\x0e\n\nRIGHT_SIDE\x10\x06\x12\r\n\tLEFT_SIDE\x10\x07\x12\x0b\n\x07PRESENT\x10\x08\x1a\x66\n\x07Storage\x12J\n\x0cstorage_type\x18\x01 \x01(\x0e\x32\x34.chromiumos.config.api.Component.Storage.StorageType\x12\x0f\n\x07size_gb\x18\x02 \x01(\r\x1a\x8c\x01\n\tBluetooth\x12=\n\tcomponent\x18\x01 \x01(\x0b\x32*.chromiumos.config.api.Component.Bluetooth\x12@\n\x07present\x18\x02 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1aN\n\nBarrelJack\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\xf7\x01\n\x04Wifi\x12T\n\x18supported_wlan_protocols\x18\x01 \x03(\x0e\x32\x32.chromiumos.config.api.Component.Wifi.WLANProtocol\x12I\n\nwifi_chips\x18\x02 \x03(\x0e\x32\x35.chromiumos.config.api.HardwareFeatures.Wifi.WifiChip\"N\n\x08WifiChip\x12\x15\n\x11WIFI_CHIP_UNKNOWN\x10\x00\x12\x15\n\x11WIRELESS_86ED801D\x10\x01\x12\x14\n\x10WIRELESS_REALTEK\x10\x02\x1a\xa0\x02\n\x06\x42utton\x12\x45\n\x06region\x18\x01 \x01(\x0e\x32\x35.chromiumos.config.api.HardwareFeatures.Button.Region\x12\x41\n\x04\x65\x64ge\x18\x02 \x01(\x0e\x32\x33.chromiumos.config.api.HardwareFeatures.Button.Edge\x12\x10\n\x08position\x18\x03 \x01(\x02\"6\n\x06Region\x12\x12\n\x0eREGION_UNKNOWN\x10\x00\x12\n\n\x06SCREEN\x10\x01\x12\x0c\n\x08KEYBOARD\x10\x02\"B\n\x04\x45\x64ge\x12\x10\n\x0c\x45\x44GE_UNKNOWN\x10\x00\x12\x08\n\x04LEFT\x10\x01\x12\t\n\x05RIGHT\x10\x02\x12\x07\n\x03TOP\x10\x03\x12\n\n\x06\x42OTTOM\x10\x04\x1a\xd3\x03\n\x12\x45mbeddedController\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12\x62\n\x07\x65\x63_type\x18\x02 \x01(\x0e\x32Q.chromiumos.config.api.HardwareFeatures.EmbeddedController.EmbeddedControllerType\x12\x41\n\x04part\x18\x03 \x01(\x0b\x32\x33.chromiumos.config.api.Component.EmbeddedController\x12J\n\x11\x66\x65\x61ture_typec_cmd\x18\x04 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12<\n\x03\x63\x62i\x18\x05 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\"J\n\x16\x45mbeddedControllerType\x12\x13\n\x0f\x45\x43_TYPE_UNKNOWN\x10\x00\x12\r\n\tEC_CHROME\x10\x01\x12\x0c\n\x08\x45\x43_WILCO\x10\x02\x1a\xe0\x01\n\x15TrustedPlatformModule\x12i\n\x08tpm_type\x18\x01 \x01(\x0e\x32W.chromiumos.config.api.HardwareFeatures.TrustedPlatformModule.TrustedPlatformModuleType\"\\\n\x19TrustedPlatformModuleType\x12\x14\n\x10TPM_TYPE_UNKNOWN\x10\x00\x12\x0f\n\x0bTHIRD_PARTY\x10\x01\x12\x0b\n\x07GSC_H1B\x10\x02\x12\x0b\n\x07GSC_H1D\x10\x03\x1aN\n\nHotwording\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\xa9\x01\n\x07\x44isplay\x12\x42\n\x04type\x18\x01 \x01(\x0e\x32\x34.chromiumos.config.api.HardwareFeatures.Display.Type\"Z\n\x04Type\x12\x10\n\x0cTYPE_UNKNOWN\x10\x00\x12\x11\n\rTYPE_INTERNAL\x10\x01\x12\x11\n\rTYPE_EXTERNAL\x10\x02\x12\x1a\n\x16TYPE_INTERNAL_EXTERNAL\x10\x03\x1aL\n\x08Touchpad\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1aX\n\x14MicrophoneMuteSwitch\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\xb6\x05\n\x07\x42\x61ttery\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12J\n\x08lifetime\x18\x02 \x01(\x0b\x32\x38.chromiumos.config.api.HardwareFeatures.Battery.Lifetime\x12J\n\x08\x63harging\x18\x03 \x01(\x0b\x32\x38.chromiumos.config.api.HardwareFeatures.Battery.Charging\x1a\x9f\x02\n\x08Lifetime\x12\x35\n\x0cshipping_min\x18\x01 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x12\x37\n\x0e\x64\x65\x65p_sleep_min\x18\x02 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x12\x34\n\x0bsuspend_min\x18\x03 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x12\x38\n\x0flucid_sleep_min\x18\x04 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x12\x33\n\nactive_min\x18\x05 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x1a\xae\x01\n\x08\x43harging\x12\x33\n\nactive_max\x18\x01 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x12\x34\n\x0bsuspend_max\x18\x02 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x12\x37\n\x0e\x64\x65\x65p_sleep_max\x18\x03 \x01(\x0b\x32\x1f.chromiumos.config.api.Duration\x1aQ\n\rPrivacyScreen\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1a\x45\n\x03Soc\x12>\n\x08\x66\x65\x61tures\x18\x01 \x03(\x0e\x32,.chromiumos.config.api.Component.Soc.Feature\x1a\x61\n\x14\x44isplayPortConverter\x12I\n\nconverters\x18\x01 \x03(\x0b\x32\x35.chromiumos.config.api.Component.DisplayPortConverter\x1aG\n\x03Hps\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1aG\n\x03PoE\x12@\n\x07present\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x1al\n\x0bPowerSupply\x12\x43\n\nbarreljack\x18\x01 \x01(\x0e\x32/.chromiumos.config.api.HardwareFeatures.Present\x12\x18\n\x10usb_min_ac_watts\x18\x02 \x01(\x05\"<\n\x07Present\x12\x13\n\x0fPRESENT_UNKNOWN\x10\x00\x12\x0b\n\x07PRESENT\x10\x01\x12\x0f\n\x0bNOT_PRESENT\x10\x02\x42*Z(go.chromium.org/chromiumos/config/go/apib\x06proto3'
   ,
-  dependencies=[chromiumos_dot_config_dot_api_dot_component__pb2.DESCRIPTOR,])
+  dependencies=[chromiumos_dot_config_dot_api_dot_component__pb2.DESCRIPTOR,google_dot_protobuf_dot_wrappers__pb2.DESCRIPTOR,])
 
 
 
@@ -92,7 +93,7 @@
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='LTE_BOARD', index=15, number=15,
+      name='CELLULAR_BOARD', index=15, number=15,
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
@@ -147,11 +148,27 @@
       name='SOC', index=28, number=28,
       serialized_options=None,
       type=None),
+    _descriptor.EnumValueDescriptor(
+      name='HPS', index=29, number=29,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='DP_CONVERTER', index=30, number=30,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='POE', index=31, number=31,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='POWER_SUPPLY', index=32, number=32,
+      serialized_options=None,
+      type=None),
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=370,
-  serialized_end=838,
+  serialized_start=402,
+  serialized_end=929,
 )
 _sym_db.RegisterEnumDescriptor(_TOPOLOGY_TYPE)
 
@@ -188,11 +205,37 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=920,
-  serialized_end=1009,
+  serialized_start=1011,
+  serialized_end=1100,
 )
 _sym_db.RegisterEnumDescriptor(_DURATION_TYPE)
 
+_HARDWAREFEATURES_CELLULAR_CELLULARTYPE = _descriptor.EnumDescriptor(
+  name='CellularType',
+  full_name='chromiumos.config.api.HardwareFeatures.Cellular.CellularType',
+  filename=None,
+  file=DESCRIPTOR,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='NOT_PRESENT', index=0, number=0,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='CELLULAR_LTE', index=1, number=1,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='CELLULAR_5G', index=2, number=2,
+      serialized_options=None,
+      type=None),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=4023,
+  serialized_end=4089,
+)
+_sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_CELLULAR_CELLULARTYPE)
+
 _HARDWAREFEATURES_AUDIO_AUDIOCODEC = _descriptor.EnumDescriptor(
   name='AudioCodec',
   full_name='chromiumos.config.api.HardwareFeatures.Audio.AudioCodec',
@@ -238,8 +281,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=4212,
-  serialized_end=4369,
+  serialized_start=5214,
+  serialized_end=5371,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_AUDIO_AUDIOCODEC)
 
@@ -288,11 +331,37 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=4372,
-  serialized_end=4525,
+  serialized_start=5374,
+  serialized_end=5527,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_AUDIO_AMPLIFIER)
 
+_HARDWAREFEATURES_AUDIO_AUDIOCONFIGSTRUCTURE = _descriptor.EnumDescriptor(
+  name='AudioConfigStructure',
+  full_name='chromiumos.config.api.HardwareFeatures.Audio.AudioConfigStructure',
+  filename=None,
+  file=DESCRIPTOR,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='AUDIO_CONFIG_STRUCTURE_NONE', index=0, number=0,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='DESIGN', index=1, number=1,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='COMMON', index=2, number=2,
+      serialized_options=None,
+      type=None),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=5529,
+  serialized_end=5608,
+)
+_sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_AUDIO_AUDIOCONFIGSTRUCTURE)
+
 _HARDWAREFEATURES_CAMERA_INTERFACE = _descriptor.EnumDescriptor(
   name='Interface',
   full_name='chromiumos.config.api.HardwareFeatures.Camera.Interface',
@@ -314,8 +383,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=4951,
-  serialized_end=5024,
+  serialized_start=6034,
+  serialized_end=6107,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_CAMERA_INTERFACE)
 
@@ -340,8 +409,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=5026,
-  serialized_end=5089,
+  serialized_start=6109,
+  serialized_end=6172,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_CAMERA_FACING)
 
@@ -374,8 +443,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=5091,
-  serialized_end=5210,
+  serialized_start=6174,
+  serialized_end=6293,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_CAMERA_ORIENTATION)
 
@@ -400,8 +469,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=5212,
-  serialized_end=5289,
+  serialized_start=6295,
+  serialized_end=6372,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_CAMERA_FLAGS)
 
@@ -446,8 +515,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=6231,
-  serialized_end=6383,
+  serialized_start=7314,
+  serialized_end=7466,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_FORMFACTOR_FORMFACTORTYPE)
 
@@ -476,8 +545,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=6471,
-  serialized_end=6541,
+  serialized_start=7554,
+  serialized_end=7624,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_STYLUS_STYLUSTYPE)
 
@@ -506,8 +575,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=6851,
-  serialized_end=6932,
+  serialized_start=7964,
+  serialized_end=8045,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_KEYBOARD_KEYBOARDTYPE)
 
@@ -556,8 +625,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=7142,
-  serialized_end=7339,
+  serialized_start=8255,
+  serialized_end=8452,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_FINGERPRINT_LOCATION)
 
@@ -582,8 +651,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=7838,
-  serialized_end=7916,
+  serialized_start=8951,
+  serialized_end=9029,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_WIFI_WIFICHIP)
 
@@ -608,8 +677,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=8085,
-  serialized_end=8139,
+  serialized_start=9198,
+  serialized_end=9252,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_BUTTON_REGION)
 
@@ -642,8 +711,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=8141,
-  serialized_end=8207,
+  serialized_start=9254,
+  serialized_end=9320,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_BUTTON_EDGE)
 
@@ -668,8 +737,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=8465,
-  serialized_end=8539,
+  serialized_start=9716,
+  serialized_end=9790,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_EMBEDDEDCONTROLLER_EMBEDDEDCONTROLLERTYPE)
 
@@ -698,8 +767,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=8674,
-  serialized_end=8766,
+  serialized_start=9925,
+  serialized_end=10017,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_TRUSTEDPLATFORMMODULE_TRUSTEDPLATFORMMODULETYPE)
 
@@ -728,8 +797,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=8928,
-  serialized_end=9018,
+  serialized_start=10179,
+  serialized_end=10269,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_DISPLAY_TYPE)
 
@@ -754,8 +823,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=10138,
-  serialized_end=10198,
+  serialized_start=11645,
+  serialized_end=11705,
 )
 _sym_db.RegisterEnumDescriptor(_HARDWAREFEATURES_PRESENT)
 
@@ -793,8 +862,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=317,
-  serialized_end=367,
+  serialized_start=349,
+  serialized_end=399,
 )
 
 _TOPOLOGY = _descriptor.Descriptor(
@@ -845,8 +914,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=103,
-  serialized_end=838,
+  serialized_start=135,
+  serialized_end=929,
 )
 
 
@@ -884,8 +953,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=841,
-  serialized_end=1009,
+  serialized_start=932,
+  serialized_end=1100,
 )
 
 
@@ -915,8 +984,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3367,
-  serialized_end=3389,
+  serialized_start=3659,
+  serialized_end=3681,
 )
 
 _HARDWAREFEATURES_USBC = _descriptor.Descriptor(
@@ -945,8 +1014,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3391,
-  serialized_end=3459,
+  serialized_start=3683,
+  serialized_end=3751,
 )
 
 _HARDWAREFEATURES_USBA = _descriptor.Descriptor(
@@ -975,36 +1044,51 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3461,
-  serialized_end=3529,
+  serialized_start=3753,
+  serialized_end=3821,
 )
 
-_HARDWAREFEATURES_LTE = _descriptor.Descriptor(
-  name='Lte',
-  full_name='chromiumos.config.api.HardwareFeatures.Lte',
+_HARDWAREFEATURES_CELLULAR = _descriptor.Descriptor(
+  name='Cellular',
+  full_name='chromiumos.config.api.HardwareFeatures.Cellular',
   filename=None,
   file=DESCRIPTOR,
   containing_type=None,
   fields=[
     _descriptor.FieldDescriptor(
-      name='present', full_name='chromiumos.config.api.HardwareFeatures.Lte.present', index=0,
+      name='present', full_name='chromiumos.config.api.HardwareFeatures.Cellular.present', index=0,
       number=1, type=14, cpp_type=8, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='model', full_name='chromiumos.config.api.HardwareFeatures.Lte.model', index=1,
+      name='model', full_name='chromiumos.config.api.HardwareFeatures.Cellular.model', index=1,
       number=2, type=9, cpp_type=9, label=1,
       has_default_value=False, default_value=b"".decode('utf-8'),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='type', full_name='chromiumos.config.api.HardwareFeatures.Cellular.type', index=2,
+      number=3, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='attach_apn_required', full_name='chromiumos.config.api.HardwareFeatures.Cellular.attach_apn_required', index=3,
+      number=4, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
   nested_types=[],
   enum_types=[
+    _HARDWAREFEATURES_CELLULAR_CELLULARTYPE,
   ],
   serialized_options=None,
   is_extendable=False,
@@ -1012,8 +1096,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3531,
-  serialized_end=3617,
+  serialized_start=3824,
+  serialized_end=4089,
 )
 
 _HARDWAREFEATURES_HDMI = _descriptor.Descriptor(
@@ -1042,8 +1126,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3619,
-  serialized_end=3691,
+  serialized_start=4091,
+  serialized_end=4163,
 )
 
 _HARDWAREFEATURES_FIRMWARECONFIGURATION = _descriptor.Descriptor(
@@ -1079,8 +1163,66 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3693,
-  serialized_end=3745,
+  serialized_start=4165,
+  serialized_end=4217,
+)
+
+_HARDWAREFEATURES_AUDIO_CARDCONFIG = _descriptor.Descriptor(
+  name='CardConfig',
+  full_name='chromiumos.config.api.HardwareFeatures.Audio.CardConfig',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='card_name', full_name='chromiumos.config.api.HardwareFeatures.Audio.CardConfig.card_name', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='ucm_suffix', full_name='chromiumos.config.api.HardwareFeatures.Audio.CardConfig.ucm_suffix', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='ucm_config', full_name='chromiumos.config.api.HardwareFeatures.Audio.CardConfig.ucm_config', index=2,
+      number=3, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='cras_config', full_name='chromiumos.config.api.HardwareFeatures.Audio.CardConfig.cras_config', index=3,
+      number=4, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='sound_card_init_config', full_name='chromiumos.config.api.HardwareFeatures.Audio.CardConfig.sound_card_init_config', index=4,
+      number=5, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=4853,
+  serialized_end=5211,
 )
 
 _HARDWAREFEATURES_AUDIO = _descriptor.Descriptor(
@@ -1132,13 +1274,28 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='card_configs', full_name='chromiumos.config.api.HardwareFeatures.Audio.card_configs', index=6,
+      number=7, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='cras_config', full_name='chromiumos.config.api.HardwareFeatures.Audio.cras_config', index=7,
+      number=8, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
-  nested_types=[],
+  nested_types=[_HARDWAREFEATURES_AUDIO_CARDCONFIG, ],
   enum_types=[
     _HARDWAREFEATURES_AUDIO_AUDIOCODEC,
     _HARDWAREFEATURES_AUDIO_AMPLIFIER,
+    _HARDWAREFEATURES_AUDIO_AUDIOCONFIGSTRUCTURE,
   ],
   serialized_options=None,
   is_extendable=False,
@@ -1146,8 +1303,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3748,
-  serialized_end=4525,
+  serialized_start=4220,
+  serialized_end=5608,
 )
 
 _HARDWAREFEATURES_CAMERA_DEVICE = _descriptor.Descriptor(
@@ -1211,8 +1368,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4611,
-  serialized_end=4949,
+  serialized_start=5694,
+  serialized_end=6032,
 )
 
 _HARDWAREFEATURES_CAMERA = _descriptor.Descriptor(
@@ -1245,8 +1402,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4528,
-  serialized_end=5289,
+  serialized_start=5611,
+  serialized_end=6372,
 )
 
 _HARDWAREFEATURES_ACCELEROMETER = _descriptor.Descriptor(
@@ -1282,8 +1439,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5292,
-  serialized_end=5460,
+  serialized_start=6375,
+  serialized_end=6543,
 )
 
 _HARDWAREFEATURES_GYROSCOPE = _descriptor.Descriptor(
@@ -1319,8 +1476,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5463,
-  serialized_end=5619,
+  serialized_start=6546,
+  serialized_end=6702,
 )
 
 _HARDWAREFEATURES_MAGNETOMETER = _descriptor.Descriptor(
@@ -1356,8 +1513,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5622,
-  serialized_end=5787,
+  serialized_start=6705,
+  serialized_end=6870,
 )
 
 _HARDWAREFEATURES_LIGHTSENSOR = _descriptor.Descriptor(
@@ -1393,8 +1550,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5790,
-  serialized_end=5952,
+  serialized_start=6873,
+  serialized_end=7035,
 )
 
 _HARDWAREFEATURES_SCREEN = _descriptor.Descriptor(
@@ -1430,8 +1587,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5955,
-  serialized_end=6125,
+  serialized_start=7038,
+  serialized_end=7208,
 )
 
 _HARDWAREFEATURES_FORMFACTOR = _descriptor.Descriptor(
@@ -1461,8 +1618,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=6128,
-  serialized_end=6383,
+  serialized_start=7211,
+  serialized_end=7466,
 )
 
 _HARDWAREFEATURES_STYLUS = _descriptor.Descriptor(
@@ -1492,8 +1649,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=6386,
-  serialized_end=6541,
+  serialized_start=7469,
+  serialized_end=7624,
 )
 
 _HARDWAREFEATURES_KEYBOARD = _descriptor.Descriptor(
@@ -1531,6 +1688,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='backlight_user_steps', full_name='chromiumos.config.api.HardwareFeatures.Keyboard.backlight_user_steps', index=4,
+      number=5, type=1, cpp_type=5, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -1544,8 +1708,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=6544,
-  serialized_end=6932,
+  serialized_start=7627,
+  serialized_end=8045,
 )
 
 _HARDWAREFEATURES_MEMORY = _descriptor.Descriptor(
@@ -1574,8 +1738,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=6934,
-  serialized_end=7008,
+  serialized_start=8047,
+  serialized_end=8121,
 )
 
 _HARDWAREFEATURES_FINGERPRINT = _descriptor.Descriptor(
@@ -1619,8 +1783,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=7011,
-  serialized_end=7339,
+  serialized_start=8124,
+  serialized_end=8452,
 )
 
 _HARDWAREFEATURES_STORAGE = _descriptor.Descriptor(
@@ -1656,8 +1820,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=7341,
-  serialized_end=7443,
+  serialized_start=8454,
+  serialized_end=8556,
 )
 
 _HARDWAREFEATURES_BLUETOOTH = _descriptor.Descriptor(
@@ -1693,8 +1857,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=7446,
-  serialized_end=7586,
+  serialized_start=8559,
+  serialized_end=8699,
 )
 
 _HARDWAREFEATURES_BARRELJACK = _descriptor.Descriptor(
@@ -1723,8 +1887,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=7588,
-  serialized_end=7666,
+  serialized_start=8701,
+  serialized_end=8779,
 )
 
 _HARDWAREFEATURES_WIFI = _descriptor.Descriptor(
@@ -1761,8 +1925,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=7669,
-  serialized_end=7916,
+  serialized_start=8782,
+  serialized_end=9029,
 )
 
 _HARDWAREFEATURES_BUTTON = _descriptor.Descriptor(
@@ -1807,8 +1971,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=7919,
-  serialized_end=8207,
+  serialized_start=9032,
+  serialized_end=9320,
 )
 
 _HARDWAREFEATURES_EMBEDDEDCONTROLLER = _descriptor.Descriptor(
@@ -1839,6 +2003,20 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='feature_typec_cmd', full_name='chromiumos.config.api.HardwareFeatures.EmbeddedController.feature_typec_cmd', index=3,
+      number=4, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='cbi', full_name='chromiumos.config.api.HardwareFeatures.EmbeddedController.cbi', index=4,
+      number=5, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -1852,8 +2030,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=8210,
-  serialized_end=8539,
+  serialized_start=9323,
+  serialized_end=9790,
 )
 
 _HARDWAREFEATURES_TRUSTEDPLATFORMMODULE = _descriptor.Descriptor(
@@ -1883,8 +2061,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=8542,
-  serialized_end=8766,
+  serialized_start=9793,
+  serialized_end=10017,
 )
 
 _HARDWAREFEATURES_HOTWORDING = _descriptor.Descriptor(
@@ -1913,8 +2091,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=8768,
-  serialized_end=8846,
+  serialized_start=10019,
+  serialized_end=10097,
 )
 
 _HARDWAREFEATURES_DISPLAY = _descriptor.Descriptor(
@@ -1944,8 +2122,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=8849,
-  serialized_end=9018,
+  serialized_start=10100,
+  serialized_end=10269,
 )
 
 _HARDWAREFEATURES_TOUCHPAD = _descriptor.Descriptor(
@@ -1974,8 +2152,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9020,
-  serialized_end=9096,
+  serialized_start=10271,
+  serialized_end=10347,
 )
 
 _HARDWAREFEATURES_MICROPHONEMUTESWITCH = _descriptor.Descriptor(
@@ -2004,8 +2182,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9098,
-  serialized_end=9186,
+  serialized_start=10349,
+  serialized_end=10437,
 )
 
 _HARDWAREFEATURES_BATTERY_LIFETIME = _descriptor.Descriptor(
@@ -2062,8 +2240,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9419,
-  serialized_end=9706,
+  serialized_start=10670,
+  serialized_end=10957,
 )
 
 _HARDWAREFEATURES_BATTERY_CHARGING = _descriptor.Descriptor(
@@ -2106,8 +2284,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9709,
-  serialized_end=9883,
+  serialized_start=10960,
+  serialized_end=11134,
 )
 
 _HARDWAREFEATURES_BATTERY = _descriptor.Descriptor(
@@ -2150,8 +2328,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9189,
-  serialized_end=9883,
+  serialized_start=10440,
+  serialized_end=11134,
 )
 
 _HARDWAREFEATURES_PRIVACYSCREEN = _descriptor.Descriptor(
@@ -2180,8 +2358,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9885,
-  serialized_end=9966,
+  serialized_start=11136,
+  serialized_end=11217,
 )
 
 _HARDWAREFEATURES_SOC = _descriptor.Descriptor(
@@ -2210,8 +2388,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=9968,
-  serialized_end=10037,
+  serialized_start=11219,
+  serialized_end=11288,
 )
 
 _HARDWAREFEATURES_DISPLAYPORTCONVERTER = _descriptor.Descriptor(
@@ -2240,8 +2418,105 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=10039,
-  serialized_end=10136,
+  serialized_start=11290,
+  serialized_end=11387,
+)
+
+_HARDWAREFEATURES_HPS = _descriptor.Descriptor(
+  name='Hps',
+  full_name='chromiumos.config.api.HardwareFeatures.Hps',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='present', full_name='chromiumos.config.api.HardwareFeatures.Hps.present', index=0,
+      number=1, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=11389,
+  serialized_end=11460,
+)
+
+_HARDWAREFEATURES_POE = _descriptor.Descriptor(
+  name='PoE',
+  full_name='chromiumos.config.api.HardwareFeatures.PoE',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='present', full_name='chromiumos.config.api.HardwareFeatures.PoE.present', index=0,
+      number=1, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=11462,
+  serialized_end=11533,
+)
+
+_HARDWAREFEATURES_POWERSUPPLY = _descriptor.Descriptor(
+  name='PowerSupply',
+  full_name='chromiumos.config.api.HardwareFeatures.PowerSupply',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='barreljack', full_name='chromiumos.config.api.HardwareFeatures.PowerSupply.barreljack', index=0,
+      number=1, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='usb_min_ac_watts', full_name='chromiumos.config.api.HardwareFeatures.PowerSupply.usb_min_ac_watts', index=1,
+      number=2, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=11535,
+  serialized_end=11643,
 )
 
 _HARDWAREFEATURES = _descriptor.Descriptor(
@@ -2266,7 +2541,7 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='lte', full_name='chromiumos.config.api.HardwareFeatures.lte', index=2,
+      name='cellular', full_name='chromiumos.config.api.HardwareFeatures.cellular', index=2,
       number=3, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
@@ -2482,10 +2757,31 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='hps', full_name='chromiumos.config.api.HardwareFeatures.hps', index=33,
+      number=34, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='poe', full_name='chromiumos.config.api.HardwareFeatures.poe', index=34,
+      number=35, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='power_supply', full_name='chromiumos.config.api.HardwareFeatures.power_supply', index=35,
+      number=36, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
-  nested_types=[_HARDWAREFEATURES_COUNT, _HARDWAREFEATURES_USBC, _HARDWAREFEATURES_USBA, _HARDWAREFEATURES_LTE, _HARDWAREFEATURES_HDMI, _HARDWAREFEATURES_FIRMWARECONFIGURATION, _HARDWAREFEATURES_AUDIO, _HARDWAREFEATURES_CAMERA, _HARDWAREFEATURES_ACCELEROMETER, _HARDWAREFEATURES_GYROSCOPE, _HARDWAREFEATURES_MAGNETOMETER, _HARDWAREFEATURES_LIGHTSENSOR, _HARDWAREFEATURES_SCREEN, _HARDWAREFEATURES_FORMFACTOR, _HARDWAREFEATURES_STYLUS, _HARDWAREFEATURES_KEYBOARD, _HARDWAREFEATURES_MEMORY, _HARDWAREFEATURES_FINGERPRINT, _HARDWAREFEATURES_STORAGE, _HARDWAREFEATURES_BLUETOOTH, _HARDWAREFEATURES_BARRELJACK, _HARDWAREFEATURES_WIFI, _HARDWAREFEATURES_BUTTON, _HARDWAREFEATURES_EMBEDDEDCONTROLLER, _HARDWAREFEATURES_TRUSTEDPLATFORMMODULE, _HARDWAREFEATURES_HOTWORDING, _HARDWAREFEATURES_DISPLAY, _HARDWAREFEATURES_TOUCHPAD, _HARDWAREFEATURES_MICROPHONEMUTESWITCH, _HARDWAREFEATURES_BATTERY, _HARDWAREFEATURES_PRIVACYSCREEN, _HARDWAREFEATURES_SOC, _HARDWAREFEATURES_DISPLAYPORTCONVERTER, ],
+  nested_types=[_HARDWAREFEATURES_COUNT, _HARDWAREFEATURES_USBC, _HARDWAREFEATURES_USBA, _HARDWAREFEATURES_CELLULAR, _HARDWAREFEATURES_HDMI, _HARDWAREFEATURES_FIRMWARECONFIGURATION, _HARDWAREFEATURES_AUDIO, _HARDWAREFEATURES_CAMERA, _HARDWAREFEATURES_ACCELEROMETER, _HARDWAREFEATURES_GYROSCOPE, _HARDWAREFEATURES_MAGNETOMETER, _HARDWAREFEATURES_LIGHTSENSOR, _HARDWAREFEATURES_SCREEN, _HARDWAREFEATURES_FORMFACTOR, _HARDWAREFEATURES_STYLUS, _HARDWAREFEATURES_KEYBOARD, _HARDWAREFEATURES_MEMORY, _HARDWAREFEATURES_FINGERPRINT, _HARDWAREFEATURES_STORAGE, _HARDWAREFEATURES_BLUETOOTH, _HARDWAREFEATURES_BARRELJACK, _HARDWAREFEATURES_WIFI, _HARDWAREFEATURES_BUTTON, _HARDWAREFEATURES_EMBEDDEDCONTROLLER, _HARDWAREFEATURES_TRUSTEDPLATFORMMODULE, _HARDWAREFEATURES_HOTWORDING, _HARDWAREFEATURES_DISPLAY, _HARDWAREFEATURES_TOUCHPAD, _HARDWAREFEATURES_MICROPHONEMUTESWITCH, _HARDWAREFEATURES_BATTERY, _HARDWAREFEATURES_PRIVACYSCREEN, _HARDWAREFEATURES_SOC, _HARDWAREFEATURES_DISPLAYPORTCONVERTER, _HARDWAREFEATURES_HPS, _HARDWAREFEATURES_POE, _HARDWAREFEATURES_POWERSUPPLY, ],
   enum_types=[
     _HARDWAREFEATURES_PRESENT,
   ],
@@ -2495,8 +2791,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1012,
-  serialized_end=10198,
+  serialized_start=1103,
+  serialized_end=11705,
 )
 
 _TOPOLOGY_DESCRIPTIONENTRY.containing_type = _TOPOLOGY
@@ -2511,20 +2807,30 @@
 _HARDWAREFEATURES_USBC.containing_type = _HARDWAREFEATURES
 _HARDWAREFEATURES_USBA.fields_by_name['count'].message_type = _HARDWAREFEATURES_COUNT
 _HARDWAREFEATURES_USBA.containing_type = _HARDWAREFEATURES
-_HARDWAREFEATURES_LTE.fields_by_name['present'].enum_type = _HARDWAREFEATURES_PRESENT
-_HARDWAREFEATURES_LTE.containing_type = _HARDWAREFEATURES
+_HARDWAREFEATURES_CELLULAR.fields_by_name['present'].enum_type = _HARDWAREFEATURES_PRESENT
+_HARDWAREFEATURES_CELLULAR.fields_by_name['type'].enum_type = _HARDWAREFEATURES_CELLULAR_CELLULARTYPE
+_HARDWAREFEATURES_CELLULAR.containing_type = _HARDWAREFEATURES
+_HARDWAREFEATURES_CELLULAR_CELLULARTYPE.containing_type = _HARDWAREFEATURES_CELLULAR
 _HARDWAREFEATURES_HDMI.fields_by_name['present'].enum_type = _HARDWAREFEATURES_PRESENT
 _HARDWAREFEATURES_HDMI.containing_type = _HARDWAREFEATURES
 _HARDWAREFEATURES_FIRMWARECONFIGURATION.containing_type = _HARDWAREFEATURES
+_HARDWAREFEATURES_AUDIO_CARDCONFIG.fields_by_name['ucm_suffix'].message_type = google_dot_protobuf_dot_wrappers__pb2._STRINGVALUE
+_HARDWAREFEATURES_AUDIO_CARDCONFIG.fields_by_name['ucm_config'].enum_type = _HARDWAREFEATURES_AUDIO_AUDIOCONFIGSTRUCTURE
+_HARDWAREFEATURES_AUDIO_CARDCONFIG.fields_by_name['cras_config'].enum_type = _HARDWAREFEATURES_AUDIO_AUDIOCONFIGSTRUCTURE
+_HARDWAREFEATURES_AUDIO_CARDCONFIG.fields_by_name['sound_card_init_config'].enum_type = _HARDWAREFEATURES_AUDIO_AUDIOCONFIGSTRUCTURE
+_HARDWAREFEATURES_AUDIO_CARDCONFIG.containing_type = _HARDWAREFEATURES_AUDIO
 _HARDWAREFEATURES_AUDIO.fields_by_name['audio_codec'].enum_type = _HARDWAREFEATURES_AUDIO_AUDIOCODEC
 _HARDWAREFEATURES_AUDIO.fields_by_name['speaker_amp'].enum_type = _HARDWAREFEATURES_AUDIO_AMPLIFIER
 _HARDWAREFEATURES_AUDIO.fields_by_name['headphone_codec'].enum_type = _HARDWAREFEATURES_AUDIO_AUDIOCODEC
 _HARDWAREFEATURES_AUDIO.fields_by_name['lid_microphone'].message_type = _HARDWAREFEATURES_COUNT
 _HARDWAREFEATURES_AUDIO.fields_by_name['base_microphone'].message_type = _HARDWAREFEATURES_COUNT
 _HARDWAREFEATURES_AUDIO.fields_by_name['speaker_amplifier'].message_type = chromiumos_dot_config_dot_api_dot_component__pb2._COMPONENT_AMPLIFIER
+_HARDWAREFEATURES_AUDIO.fields_by_name['card_configs'].message_type = _HARDWAREFEATURES_AUDIO_CARDCONFIG
+_HARDWAREFEATURES_AUDIO.fields_by_name['cras_config'].enum_type = _HARDWAREFEATURES_AUDIO_AUDIOCONFIGSTRUCTURE
 _HARDWAREFEATURES_AUDIO.containing_type = _HARDWAREFEATURES
 _HARDWAREFEATURES_AUDIO_AUDIOCODEC.containing_type = _HARDWAREFEATURES_AUDIO
 _HARDWAREFEATURES_AUDIO_AMPLIFIER.containing_type = _HARDWAREFEATURES_AUDIO
+_HARDWAREFEATURES_AUDIO_AUDIOCONFIGSTRUCTURE.containing_type = _HARDWAREFEATURES_AUDIO
 _HARDWAREFEATURES_CAMERA_DEVICE.fields_by_name['interface'].enum_type = _HARDWAREFEATURES_CAMERA_INTERFACE
 _HARDWAREFEATURES_CAMERA_DEVICE.fields_by_name['facing'].enum_type = _HARDWAREFEATURES_CAMERA_FACING
 _HARDWAREFEATURES_CAMERA_DEVICE.fields_by_name['orientation'].enum_type = _HARDWAREFEATURES_CAMERA_ORIENTATION
@@ -2587,6 +2893,8 @@
 _HARDWAREFEATURES_EMBEDDEDCONTROLLER.fields_by_name['present'].enum_type = _HARDWAREFEATURES_PRESENT
 _HARDWAREFEATURES_EMBEDDEDCONTROLLER.fields_by_name['ec_type'].enum_type = _HARDWAREFEATURES_EMBEDDEDCONTROLLER_EMBEDDEDCONTROLLERTYPE
 _HARDWAREFEATURES_EMBEDDEDCONTROLLER.fields_by_name['part'].message_type = chromiumos_dot_config_dot_api_dot_component__pb2._COMPONENT_EMBEDDEDCONTROLLER
+_HARDWAREFEATURES_EMBEDDEDCONTROLLER.fields_by_name['feature_typec_cmd'].enum_type = _HARDWAREFEATURES_PRESENT
+_HARDWAREFEATURES_EMBEDDEDCONTROLLER.fields_by_name['cbi'].enum_type = _HARDWAREFEATURES_PRESENT
 _HARDWAREFEATURES_EMBEDDEDCONTROLLER.containing_type = _HARDWAREFEATURES
 _HARDWAREFEATURES_EMBEDDEDCONTROLLER_EMBEDDEDCONTROLLERTYPE.containing_type = _HARDWAREFEATURES_EMBEDDEDCONTROLLER
 _HARDWAREFEATURES_TRUSTEDPLATFORMMODULE.fields_by_name['tpm_type'].enum_type = _HARDWAREFEATURES_TRUSTEDPLATFORMMODULE_TRUSTEDPLATFORMMODULETYPE
@@ -2621,9 +2929,15 @@
 _HARDWAREFEATURES_SOC.containing_type = _HARDWAREFEATURES
 _HARDWAREFEATURES_DISPLAYPORTCONVERTER.fields_by_name['converters'].message_type = chromiumos_dot_config_dot_api_dot_component__pb2._COMPONENT_DISPLAYPORTCONVERTER
 _HARDWAREFEATURES_DISPLAYPORTCONVERTER.containing_type = _HARDWAREFEATURES
+_HARDWAREFEATURES_HPS.fields_by_name['present'].enum_type = _HARDWAREFEATURES_PRESENT
+_HARDWAREFEATURES_HPS.containing_type = _HARDWAREFEATURES
+_HARDWAREFEATURES_POE.fields_by_name['present'].enum_type = _HARDWAREFEATURES_PRESENT
+_HARDWAREFEATURES_POE.containing_type = _HARDWAREFEATURES
+_HARDWAREFEATURES_POWERSUPPLY.fields_by_name['barreljack'].enum_type = _HARDWAREFEATURES_PRESENT
+_HARDWAREFEATURES_POWERSUPPLY.containing_type = _HARDWAREFEATURES
 _HARDWAREFEATURES.fields_by_name['usb_c'].message_type = _HARDWAREFEATURES_USBC
 _HARDWAREFEATURES.fields_by_name['usb_a'].message_type = _HARDWAREFEATURES_USBA
-_HARDWAREFEATURES.fields_by_name['lte'].message_type = _HARDWAREFEATURES_LTE
+_HARDWAREFEATURES.fields_by_name['cellular'].message_type = _HARDWAREFEATURES_CELLULAR
 _HARDWAREFEATURES.fields_by_name['hdmi'].message_type = _HARDWAREFEATURES_HDMI
 _HARDWAREFEATURES.fields_by_name['fw_config'].message_type = _HARDWAREFEATURES_FIRMWARECONFIGURATION
 _HARDWAREFEATURES.fields_by_name['audio'].message_type = _HARDWAREFEATURES_AUDIO
@@ -2654,6 +2968,9 @@
 _HARDWAREFEATURES.fields_by_name['privacy_screen'].message_type = _HARDWAREFEATURES_PRIVACYSCREEN
 _HARDWAREFEATURES.fields_by_name['soc'].message_type = _HARDWAREFEATURES_SOC
 _HARDWAREFEATURES.fields_by_name['dp_converter'].message_type = _HARDWAREFEATURES_DISPLAYPORTCONVERTER
+_HARDWAREFEATURES.fields_by_name['hps'].message_type = _HARDWAREFEATURES_HPS
+_HARDWAREFEATURES.fields_by_name['poe'].message_type = _HARDWAREFEATURES_POE
+_HARDWAREFEATURES.fields_by_name['power_supply'].message_type = _HARDWAREFEATURES_POWERSUPPLY
 _HARDWAREFEATURES_PRESENT.containing_type = _HARDWAREFEATURES
 DESCRIPTOR.message_types_by_name['Topology'] = _TOPOLOGY
 DESCRIPTOR.message_types_by_name['Duration'] = _DURATION
@@ -2705,10 +3022,10 @@
     })
   ,
 
-  'Lte' : _reflection.GeneratedProtocolMessageType('Lte', (_message.Message,), {
-    'DESCRIPTOR' : _HARDWAREFEATURES_LTE,
+  'Cellular' : _reflection.GeneratedProtocolMessageType('Cellular', (_message.Message,), {
+    'DESCRIPTOR' : _HARDWAREFEATURES_CELLULAR,
     '__module__' : 'chromiumos.config.api.topology_pb2'
-    # @@protoc_insertion_point(class_scope:chromiumos.config.api.HardwareFeatures.Lte)
+    # @@protoc_insertion_point(class_scope:chromiumos.config.api.HardwareFeatures.Cellular)
     })
   ,
 
@@ -2727,6 +3044,13 @@
   ,
 
   'Audio' : _reflection.GeneratedProtocolMessageType('Audio', (_message.Message,), {
+
+    'CardConfig' : _reflection.GeneratedProtocolMessageType('CardConfig', (_message.Message,), {
+      'DESCRIPTOR' : _HARDWAREFEATURES_AUDIO_CARDCONFIG,
+      '__module__' : 'chromiumos.config.api.topology_pb2'
+      # @@protoc_insertion_point(class_scope:chromiumos.config.api.HardwareFeatures.Audio.CardConfig)
+      })
+    ,
     'DESCRIPTOR' : _HARDWAREFEATURES_AUDIO,
     '__module__' : 'chromiumos.config.api.topology_pb2'
     # @@protoc_insertion_point(class_scope:chromiumos.config.api.HardwareFeatures.Audio)
@@ -2935,6 +3259,27 @@
     # @@protoc_insertion_point(class_scope:chromiumos.config.api.HardwareFeatures.DisplayPortConverter)
     })
   ,
+
+  'Hps' : _reflection.GeneratedProtocolMessageType('Hps', (_message.Message,), {
+    'DESCRIPTOR' : _HARDWAREFEATURES_HPS,
+    '__module__' : 'chromiumos.config.api.topology_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.config.api.HardwareFeatures.Hps)
+    })
+  ,
+
+  'PoE' : _reflection.GeneratedProtocolMessageType('PoE', (_message.Message,), {
+    'DESCRIPTOR' : _HARDWAREFEATURES_POE,
+    '__module__' : 'chromiumos.config.api.topology_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.config.api.HardwareFeatures.PoE)
+    })
+  ,
+
+  'PowerSupply' : _reflection.GeneratedProtocolMessageType('PowerSupply', (_message.Message,), {
+    'DESCRIPTOR' : _HARDWAREFEATURES_POWERSUPPLY,
+    '__module__' : 'chromiumos.config.api.topology_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.config.api.HardwareFeatures.PowerSupply)
+    })
+  ,
   'DESCRIPTOR' : _HARDWAREFEATURES,
   '__module__' : 'chromiumos.config.api.topology_pb2'
   # @@protoc_insertion_point(class_scope:chromiumos.config.api.HardwareFeatures)
@@ -2943,10 +3288,11 @@
 _sym_db.RegisterMessage(HardwareFeatures.Count)
 _sym_db.RegisterMessage(HardwareFeatures.UsbC)
 _sym_db.RegisterMessage(HardwareFeatures.UsbA)
-_sym_db.RegisterMessage(HardwareFeatures.Lte)
+_sym_db.RegisterMessage(HardwareFeatures.Cellular)
 _sym_db.RegisterMessage(HardwareFeatures.Hdmi)
 _sym_db.RegisterMessage(HardwareFeatures.FirmwareConfiguration)
 _sym_db.RegisterMessage(HardwareFeatures.Audio)
+_sym_db.RegisterMessage(HardwareFeatures.Audio.CardConfig)
 _sym_db.RegisterMessage(HardwareFeatures.Camera)
 _sym_db.RegisterMessage(HardwareFeatures.Camera.Device)
 _sym_db.RegisterMessage(HardwareFeatures.Accelerometer)
@@ -2976,6 +3322,9 @@
 _sym_db.RegisterMessage(HardwareFeatures.PrivacyScreen)
 _sym_db.RegisterMessage(HardwareFeatures.Soc)
 _sym_db.RegisterMessage(HardwareFeatures.DisplayPortConverter)
+_sym_db.RegisterMessage(HardwareFeatures.Hps)
+_sym_db.RegisterMessage(HardwareFeatures.PoE)
+_sym_db.RegisterMessage(HardwareFeatures.PowerSupply)
 
 
 DESCRIPTOR._options = None
diff --git a/api/gen_sdk/chromiumos/config/public_replication/testdata/public_replication_testdata_pb2.py b/api/gen_sdk/chromiumos/config/public_replication/testdata/public_replication_testdata_pb2.py
index 6298d93..d2fd341 100644
--- a/api/gen_sdk/chromiumos/config/public_replication/testdata/public_replication_testdata_pb2.py
+++ b/api/gen_sdk/chromiumos/config/public_replication/testdata/public_replication_testdata_pb2.py
@@ -19,7 +19,7 @@
   package='chromiumos.config.public_replication.testdata',
   syntax='proto3',
   serialized_options=b'Z@go.chromium.org/chromiumos/config/go/public_replication/testdata',
-  serialized_pb=b'\nOchromiumos/config/public_replication/testdata/public_replication_testdata.proto\x12-chromiumos.config.public_replication.testdata\x1a=chromiumos/config/public_replication/public_replication.proto\"\x9b\x02\n\x19PublicReplicationTestdata\x12S\n\x12public_replication\x18\x01 \x01(\x0b\x32\x37.chromiumos.config.public_replication.PublicReplication\x12\x0c\n\x04str1\x18\x02 \x01(\t\x12\x0c\n\x04str2\x18\x03 \x01(\t\x12`\n\x04map1\x18\x04 \x03(\x0b\x32R.chromiumos.config.public_replication.testdata.PublicReplicationTestdata.Map1Entry\x1a+\n\tMap1Entry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\"\xe5\x01\n\x10WrapperTestdata1\x12\n\n\x02n1\x18\x01 \x01(\x05\x12]\n\x0bpr_testdata\x18\x02 \x01(\x0b\x32H.chromiumos.config.public_replication.testdata.PublicReplicationTestdata\x12\x66\n\x14repeated_pr_testdata\x18\x03 \x03(\x0b\x32H.chromiumos.config.public_replication.testdata.PublicReplicationTestdata\"n\n\x10WrapperTestdata2\x12Z\n\x11wrapper_testdata1\x18\x01 \x01(\x0b\x32?.chromiumos.config.public_replication.testdata.WrapperTestdata1\"\xd2\x01\n\x10WrapperTestdata3\x12S\n\x12public_replication\x18\x01 \x01(\x0b\x32\x37.chromiumos.config.public_replication.PublicReplication\x12\n\n\x02\x62\x31\x18\x02 \x01(\x08\x12]\n\x0bpr_testdata\x18\x03 \x01(\x0b\x32H.chromiumos.config.public_replication.testdata.PublicReplicationTestdata\"z\n\x10RecursiveMessage\x12\n\n\x02\x62\x31\x18\x01 \x01(\x08\x12Z\n\x11recursive_message\x18\x02 \x01(\x0b\x32?.chromiumos.config.public_replication.testdata.RecursiveMessageBBZ@go.chromium.org/chromiumos/config/go/public_replication/testdatab\x06proto3'
+  serialized_pb=b'\nOchromiumos/config/public_replication/testdata/public_replication_testdata.proto\x12-chromiumos.config.public_replication.testdata\x1a=chromiumos/config/public_replication/public_replication.proto\"\x9b\x02\n\x19PublicReplicationTestdata\x12S\n\x12public_replication\x18\x01 \x01(\x0b\x32\x37.chromiumos.config.public_replication.PublicReplication\x12\x0c\n\x04str1\x18\x02 \x01(\t\x12\x0c\n\x04str2\x18\x03 \x01(\t\x12`\n\x04map1\x18\x04 \x03(\x0b\x32R.chromiumos.config.public_replication.testdata.PublicReplicationTestdata.Map1Entry\x1a+\n\tMap1Entry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\"\xe5\x01\n\x10WrapperTestdata1\x12\n\n\x02n1\x18\x01 \x01(\x05\x12]\n\x0bpr_testdata\x18\x02 \x01(\x0b\x32H.chromiumos.config.public_replication.testdata.PublicReplicationTestdata\x12\x66\n\x14repeated_pr_testdata\x18\x03 \x03(\x0b\x32H.chromiumos.config.public_replication.testdata.PublicReplicationTestdata\"n\n\x10WrapperTestdata2\x12Z\n\x11wrapper_testdata1\x18\x01 \x01(\x0b\x32?.chromiumos.config.public_replication.testdata.WrapperTestdata1\"\xd2\x01\n\x10WrapperTestdata3\x12S\n\x12public_replication\x18\x01 \x01(\x0b\x32\x37.chromiumos.config.public_replication.PublicReplication\x12\n\n\x02\x62\x31\x18\x02 \x01(\x08\x12]\n\x0bpr_testdata\x18\x03 \x01(\x0b\x32H.chromiumos.config.public_replication.testdata.PublicReplicationTestdata\"z\n\x10RecursiveMessage\x12\n\n\x02\x62\x31\x18\x01 \x01(\x08\x12Z\n\x11recursive_message\x18\x02 \x01(\x0b\x32?.chromiumos.config.public_replication.testdata.RecursiveMessage\"\xe3\x01\n\x0ePrivateMessage\x12T\n\x06\x63onfig\x18\x01 \x01(\x0b\x32\x44.chromiumos.config.public_replication.testdata.PrivateMessage.Config\x1a{\n\x06\x43onfig\x12Z\n\x07payload\x18\x01 \x03(\x0b\x32I.chromiumos.config.public_replication.testdata.PrivateMessage.Config.Test\x1a\x15\n\x04Test\x12\r\n\x05\x62ools\x18\x01 \x01(\x08\"n\n\x14NestedPrivateMessage\x12V\n\x0fnested_messages\x18\x01 \x01(\x0b\x32=.chromiumos.config.public_replication.testdata.PrivateMessage\"v\n\x1cNestedRepeatedPrivateMessage\x12V\n\x0fnested_messages\x18\x01 \x03(\x0b\x32=.chromiumos.config.public_replication.testdata.PrivateMessageBBZ@go.chromium.org/chromiumos/config/go/public_replication/testdatab\x06proto3'
   ,
   dependencies=[chromiumos_dot_config_dot_public__replication_dot_public__replication__pb2.DESCRIPTOR,])
 
@@ -273,6 +273,159 @@
   serialized_end=1158,
 )
 
+
+_PRIVATEMESSAGE_CONFIG_TEST = _descriptor.Descriptor(
+  name='Test',
+  full_name='chromiumos.config.public_replication.testdata.PrivateMessage.Config.Test',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='bools', full_name='chromiumos.config.public_replication.testdata.PrivateMessage.Config.Test.bools', index=0,
+      number=1, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1367,
+  serialized_end=1388,
+)
+
+_PRIVATEMESSAGE_CONFIG = _descriptor.Descriptor(
+  name='Config',
+  full_name='chromiumos.config.public_replication.testdata.PrivateMessage.Config',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='payload', full_name='chromiumos.config.public_replication.testdata.PrivateMessage.Config.payload', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[_PRIVATEMESSAGE_CONFIG_TEST, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1265,
+  serialized_end=1388,
+)
+
+_PRIVATEMESSAGE = _descriptor.Descriptor(
+  name='PrivateMessage',
+  full_name='chromiumos.config.public_replication.testdata.PrivateMessage',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='config', full_name='chromiumos.config.public_replication.testdata.PrivateMessage.config', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[_PRIVATEMESSAGE_CONFIG, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1161,
+  serialized_end=1388,
+)
+
+
+_NESTEDPRIVATEMESSAGE = _descriptor.Descriptor(
+  name='NestedPrivateMessage',
+  full_name='chromiumos.config.public_replication.testdata.NestedPrivateMessage',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='nested_messages', full_name='chromiumos.config.public_replication.testdata.NestedPrivateMessage.nested_messages', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1390,
+  serialized_end=1500,
+)
+
+
+_NESTEDREPEATEDPRIVATEMESSAGE = _descriptor.Descriptor(
+  name='NestedRepeatedPrivateMessage',
+  full_name='chromiumos.config.public_replication.testdata.NestedRepeatedPrivateMessage',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='nested_messages', full_name='chromiumos.config.public_replication.testdata.NestedRepeatedPrivateMessage.nested_messages', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1502,
+  serialized_end=1620,
+)
+
 _PUBLICREPLICATIONTESTDATA_MAP1ENTRY.containing_type = _PUBLICREPLICATIONTESTDATA
 _PUBLICREPLICATIONTESTDATA.fields_by_name['public_replication'].message_type = chromiumos_dot_config_dot_public__replication_dot_public__replication__pb2._PUBLICREPLICATION
 _PUBLICREPLICATIONTESTDATA.fields_by_name['map1'].message_type = _PUBLICREPLICATIONTESTDATA_MAP1ENTRY
@@ -282,11 +435,20 @@
 _WRAPPERTESTDATA3.fields_by_name['public_replication'].message_type = chromiumos_dot_config_dot_public__replication_dot_public__replication__pb2._PUBLICREPLICATION
 _WRAPPERTESTDATA3.fields_by_name['pr_testdata'].message_type = _PUBLICREPLICATIONTESTDATA
 _RECURSIVEMESSAGE.fields_by_name['recursive_message'].message_type = _RECURSIVEMESSAGE
+_PRIVATEMESSAGE_CONFIG_TEST.containing_type = _PRIVATEMESSAGE_CONFIG
+_PRIVATEMESSAGE_CONFIG.fields_by_name['payload'].message_type = _PRIVATEMESSAGE_CONFIG_TEST
+_PRIVATEMESSAGE_CONFIG.containing_type = _PRIVATEMESSAGE
+_PRIVATEMESSAGE.fields_by_name['config'].message_type = _PRIVATEMESSAGE_CONFIG
+_NESTEDPRIVATEMESSAGE.fields_by_name['nested_messages'].message_type = _PRIVATEMESSAGE
+_NESTEDREPEATEDPRIVATEMESSAGE.fields_by_name['nested_messages'].message_type = _PRIVATEMESSAGE
 DESCRIPTOR.message_types_by_name['PublicReplicationTestdata'] = _PUBLICREPLICATIONTESTDATA
 DESCRIPTOR.message_types_by_name['WrapperTestdata1'] = _WRAPPERTESTDATA1
 DESCRIPTOR.message_types_by_name['WrapperTestdata2'] = _WRAPPERTESTDATA2
 DESCRIPTOR.message_types_by_name['WrapperTestdata3'] = _WRAPPERTESTDATA3
 DESCRIPTOR.message_types_by_name['RecursiveMessage'] = _RECURSIVEMESSAGE
+DESCRIPTOR.message_types_by_name['PrivateMessage'] = _PRIVATEMESSAGE
+DESCRIPTOR.message_types_by_name['NestedPrivateMessage'] = _NESTEDPRIVATEMESSAGE
+DESCRIPTOR.message_types_by_name['NestedRepeatedPrivateMessage'] = _NESTEDREPEATEDPRIVATEMESSAGE
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
 PublicReplicationTestdata = _reflection.GeneratedProtocolMessageType('PublicReplicationTestdata', (_message.Message,), {
@@ -332,6 +494,43 @@
   })
 _sym_db.RegisterMessage(RecursiveMessage)
 
+PrivateMessage = _reflection.GeneratedProtocolMessageType('PrivateMessage', (_message.Message,), {
+
+  'Config' : _reflection.GeneratedProtocolMessageType('Config', (_message.Message,), {
+
+    'Test' : _reflection.GeneratedProtocolMessageType('Test', (_message.Message,), {
+      'DESCRIPTOR' : _PRIVATEMESSAGE_CONFIG_TEST,
+      '__module__' : 'chromiumos.config.public_replication.testdata.public_replication_testdata_pb2'
+      # @@protoc_insertion_point(class_scope:chromiumos.config.public_replication.testdata.PrivateMessage.Config.Test)
+      })
+    ,
+    'DESCRIPTOR' : _PRIVATEMESSAGE_CONFIG,
+    '__module__' : 'chromiumos.config.public_replication.testdata.public_replication_testdata_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.config.public_replication.testdata.PrivateMessage.Config)
+    })
+  ,
+  'DESCRIPTOR' : _PRIVATEMESSAGE,
+  '__module__' : 'chromiumos.config.public_replication.testdata.public_replication_testdata_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.config.public_replication.testdata.PrivateMessage)
+  })
+_sym_db.RegisterMessage(PrivateMessage)
+_sym_db.RegisterMessage(PrivateMessage.Config)
+_sym_db.RegisterMessage(PrivateMessage.Config.Test)
+
+NestedPrivateMessage = _reflection.GeneratedProtocolMessageType('NestedPrivateMessage', (_message.Message,), {
+  'DESCRIPTOR' : _NESTEDPRIVATEMESSAGE,
+  '__module__' : 'chromiumos.config.public_replication.testdata.public_replication_testdata_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.config.public_replication.testdata.NestedPrivateMessage)
+  })
+_sym_db.RegisterMessage(NestedPrivateMessage)
+
+NestedRepeatedPrivateMessage = _reflection.GeneratedProtocolMessageType('NestedRepeatedPrivateMessage', (_message.Message,), {
+  'DESCRIPTOR' : _NESTEDREPEATEDPRIVATEMESSAGE,
+  '__module__' : 'chromiumos.config.public_replication.testdata.public_replication_testdata_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.config.public_replication.testdata.NestedRepeatedPrivateMessage)
+  })
+_sym_db.RegisterMessage(NestedRepeatedPrivateMessage)
+
 
 DESCRIPTOR._options = None
 _PUBLICREPLICATIONTESTDATA_MAP1ENTRY._options = None
diff --git a/api/gen_sdk/chromiumos/greenness_pb2.py b/api/gen_sdk/chromiumos/greenness_pb2.py
index 92b1837..2a1cb14 100644
--- a/api/gen_sdk/chromiumos/greenness_pb2.py
+++ b/api/gen_sdk/chromiumos/greenness_pb2.py
@@ -18,11 +18,33 @@
   package='chromiumos',
   syntax='proto3',
   serialized_options=b'\n!com.google.chrome.crosinfra.protoZ4go.chromium.org/chromiumos/infra/proto/go/chromiumos',
-  serialized_pb=b'\n\x1a\x63hromiumos/greenness.proto\x12\nchromiumos\"\x9f\x01\n\x12\x41ggregateGreenness\x12\x18\n\x10\x61ggregate_metric\x18\x01 \x01(\x03\x12\x42\n\x10target_greenness\x18\x02 \x03(\x0b\x32(.chromiumos.AggregateGreenness.Greenness\x1a+\n\tGreenness\x12\x0e\n\x06target\x18\x01 \x01(\t\x12\x0e\n\x06metric\x18\x02 \x01(\x03\x42Y\n!com.google.chrome.crosinfra.protoZ4go.chromium.org/chromiumos/infra/proto/go/chromiumosb\x06proto3'
+  serialized_pb=b'\n\x1a\x63hromiumos/greenness.proto\x12\nchromiumos\"\x8f\x02\n\x12\x41ggregateGreenness\x12\x18\n\x10\x61ggregate_metric\x18\x01 \x01(\x03\x12\x42\n\x10target_greenness\x18\x02 \x03(\x0b\x32(.chromiumos.AggregateGreenness.Greenness\x1a\x9a\x01\n\tGreenness\x12\x0e\n\x06target\x18\x01 \x01(\t\x12\x0e\n\x06metric\x18\x02 \x01(\x03\x12\x41\n\x07\x63ontext\x18\x03 \x01(\x0e\x32\x30.chromiumos.AggregateGreenness.Greenness.Context\"*\n\x07\x43ontext\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\x0e\n\nIRRELEVANT\x10\x01\x42Y\n!com.google.chrome.crosinfra.protoZ4go.chromium.org/chromiumos/infra/proto/go/chromiumosb\x06proto3'
 )
 
 
 
+_AGGREGATEGREENNESS_GREENNESS_CONTEXT = _descriptor.EnumDescriptor(
+  name='Context',
+  full_name='chromiumos.AggregateGreenness.Greenness.Context',
+  filename=None,
+  file=DESCRIPTOR,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='UNSPECIFIED', index=0, number=0,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='IRRELEVANT', index=1, number=1,
+      serialized_options=None,
+      type=None),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=272,
+  serialized_end=314,
+)
+_sym_db.RegisterEnumDescriptor(_AGGREGATEGREENNESS_GREENNESS_CONTEXT)
+
 
 _AGGREGATEGREENNESS_GREENNESS = _descriptor.Descriptor(
   name='Greenness',
@@ -45,11 +67,19 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='context', full_name='chromiumos.AggregateGreenness.Greenness.context', index=2,
+      number=3, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
   nested_types=[],
   enum_types=[
+    _AGGREGATEGREENNESS_GREENNESS_CONTEXT,
   ],
   serialized_options=None,
   is_extendable=False,
@@ -57,8 +87,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=159,
-  serialized_end=202,
+  serialized_start=160,
+  serialized_end=314,
 )
 
 _AGGREGATEGREENNESS = _descriptor.Descriptor(
@@ -95,10 +125,12 @@
   oneofs=[
   ],
   serialized_start=43,
-  serialized_end=202,
+  serialized_end=314,
 )
 
+_AGGREGATEGREENNESS_GREENNESS.fields_by_name['context'].enum_type = _AGGREGATEGREENNESS_GREENNESS_CONTEXT
 _AGGREGATEGREENNESS_GREENNESS.containing_type = _AGGREGATEGREENNESS
+_AGGREGATEGREENNESS_GREENNESS_CONTEXT.containing_type = _AGGREGATEGREENNESS_GREENNESS
 _AGGREGATEGREENNESS.fields_by_name['target_greenness'].message_type = _AGGREGATEGREENNESS_GREENNESS
 DESCRIPTOR.message_types_by_name['AggregateGreenness'] = _AGGREGATEGREENNESS
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
diff --git a/api/gen_sdk/chromiumos/storage_path_pb2.py b/api/gen_sdk/chromiumos/storage_path_pb2.py
index be59044..74e34d7 100644
--- a/api/gen_sdk/chromiumos/storage_path_pb2.py
+++ b/api/gen_sdk/chromiumos/storage_path_pb2.py
@@ -17,8 +17,8 @@
   name='chromiumos/storage_path.proto',
   package='chromiumos',
   syntax='proto3',
-  serialized_options=b'Z$go.chromium.org/chromiumos/config/go',
-  serialized_pb=b'\n\x1d\x63hromiumos/storage_path.proto\x12\nchromiumos\"\x89\x01\n\x0bStoragePath\x12\x33\n\thost_type\x18\x01 \x01(\x0e\x32 .chromiumos.StoragePath.HostType\x12\x0c\n\x04path\x18\x02 \x01(\t\"7\n\x08HostType\x12\x18\n\x14HOSTTYPE_UNSPECIFIED\x10\x00\x12\t\n\x05LOCAL\x10\x01\x12\x06\n\x02GS\x10\x02\x42&Z$go.chromium.org/chromiumos/config/gob\x06proto3'
+  serialized_options=b'Z(go.chromium.org/chromiumos/config/go;_go',
+  serialized_pb=b'\n\x1d\x63hromiumos/storage_path.proto\x12\nchromiumos\"\x89\x01\n\x0bStoragePath\x12\x33\n\thost_type\x18\x01 \x01(\x0e\x32 .chromiumos.StoragePath.HostType\x12\x0c\n\x04path\x18\x02 \x01(\t\"7\n\x08HostType\x12\x18\n\x14HOSTTYPE_UNSPECIFIED\x10\x00\x12\t\n\x05LOCAL\x10\x01\x12\x06\n\x02GS\x10\x02\x42*Z(go.chromium.org/chromiumos/config/go;_gob\x06proto3'
 )
 
 
diff --git a/api/gen_sdk/chromiumos/test/api/cros_publish_cli_pb2.py b/api/gen_sdk/chromiumos/test/api/cros_publish_cli_pb2.py
new file mode 100644
index 0000000..08709b8
--- /dev/null
+++ b/api/gen_sdk/chromiumos/test/api/cros_publish_cli_pb2.py
@@ -0,0 +1,129 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: chromiumos/test/api/cros_publish_cli.proto
+
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='chromiumos/test/api/cros_publish_cli.proto',
+  package='chromiumos.test.api',
+  syntax='proto3',
+  serialized_options=b'Z-go.chromium.org/chromiumos/config/go/test/api',
+  serialized_pb=b'\n*chromiumos/test/api/cros_publish_cli.proto\x12\x13\x63hromiumos.test.api\"C\n\x12\x43rosPublishRequest\x12\x14\n\x0cgs_directory\x18\x01 \x01(\t\x12\x17\n\x0flocal_directory\x18\x02 \x01(\t\"K\n\x13\x43rosPublishResponse\x12\x0e\n\x06gs_url\x18\x01 \x01(\t\x12\r\n\x05\x65rror\x18\x02 \x01(\x08\x12\x15\n\rerror_message\x18\x03 \x01(\tB/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
+)
+
+
+
+
+_CROSPUBLISHREQUEST = _descriptor.Descriptor(
+  name='CrosPublishRequest',
+  full_name='chromiumos.test.api.CrosPublishRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='gs_directory', full_name='chromiumos.test.api.CrosPublishRequest.gs_directory', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='local_directory', full_name='chromiumos.test.api.CrosPublishRequest.local_directory', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=67,
+  serialized_end=134,
+)
+
+
+_CROSPUBLISHRESPONSE = _descriptor.Descriptor(
+  name='CrosPublishResponse',
+  full_name='chromiumos.test.api.CrosPublishResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='gs_url', full_name='chromiumos.test.api.CrosPublishResponse.gs_url', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='error', full_name='chromiumos.test.api.CrosPublishResponse.error', index=1,
+      number=2, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='error_message', full_name='chromiumos.test.api.CrosPublishResponse.error_message', index=2,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=136,
+  serialized_end=211,
+)
+
+DESCRIPTOR.message_types_by_name['CrosPublishRequest'] = _CROSPUBLISHREQUEST
+DESCRIPTOR.message_types_by_name['CrosPublishResponse'] = _CROSPUBLISHRESPONSE
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+CrosPublishRequest = _reflection.GeneratedProtocolMessageType('CrosPublishRequest', (_message.Message,), {
+  'DESCRIPTOR' : _CROSPUBLISHREQUEST,
+  '__module__' : 'chromiumos.test.api.cros_publish_cli_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.CrosPublishRequest)
+  })
+_sym_db.RegisterMessage(CrosPublishRequest)
+
+CrosPublishResponse = _reflection.GeneratedProtocolMessageType('CrosPublishResponse', (_message.Message,), {
+  'DESCRIPTOR' : _CROSPUBLISHRESPONSE,
+  '__module__' : 'chromiumos.test.api.cros_publish_cli_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.CrosPublishResponse)
+  })
+_sym_db.RegisterMessage(CrosPublishResponse)
+
+
+DESCRIPTOR._options = None
+# @@protoc_insertion_point(module_scope)
diff --git a/api/gen_sdk/chromiumos/test/api/cros_tool_runner_cli_pb2.py b/api/gen_sdk/chromiumos/test/api/cros_tool_runner_cli_pb2.py
index 10d927f..a3f157b 100644
--- a/api/gen_sdk/chromiumos/test/api/cros_tool_runner_cli_pb2.py
+++ b/api/gen_sdk/chromiumos/test/api/cros_tool_runner_cli_pb2.py
@@ -24,7 +24,7 @@
   package='chromiumos.test.api',
   syntax='proto3',
   serialized_options=b'Z-go.chromium.org/chromiumos/config/go/test/api',
-  serialized_pb=b'\n.chromiumos/test/api/cros_tool_runner_cli.proto\x12\x13\x63hromiumos.test.api\x1a)chromiumos/test/api/provision_state.proto\x1a,chromiumos/test/api/cros_provision_cli.proto\x1a*chromiumos/test/api/test_case_result.proto\x1a$chromiumos/test/api/test_suite.proto\x1a!chromiumos/test/lab/api/dut.proto\x1a)chromiumos/test/lab/api/ip_endpoint.proto\"\xb5\x02\n\x1e\x43rosToolRunnerProvisionRequest\x12K\n\x07\x64\x65vices\x18\x01 \x03(\x0b\x32:.chromiumos.test.api.CrosToolRunnerProvisionRequest.Device\x12=\n\x10inventory_server\x18\x02 \x01(\x0b\x32#.chromiumos.test.lab.api.IpEndpoint\x12\x14\n\x0c\x61rtifact_dir\x18\x03 \x01(\t\x1aq\n\x06\x44\x65vice\x12)\n\x03\x64ut\x18\x01 \x01(\x0b\x32\x1c.chromiumos.test.lab.api.Dut\x12<\n\x0fprovision_state\x18\x02 \x01(\x0b\x32#.chromiumos.test.api.ProvisionState\"`\n\x1f\x43rosToolRunnerProvisionResponse\x12=\n\tresponses\x18\x01 \x03(\x0b\x32*.chromiumos.test.api.CrosProvisionResponse\"\x8e\x02\n\x19\x43rosToolRunnerTestRequest\x12\x33\n\x0btest_suites\x18\x01 \x03(\x0b\x32\x1e.chromiumos.test.api.TestSuite\x12\x31\n\x0bprimary_dut\x18\x02 \x01(\x0b\x32\x1c.chromiumos.test.lab.api.Dut\x12\x34\n\x0e\x63ompanion_duts\x18\x03 \x03(\x0b\x32\x1c.chromiumos.test.lab.api.Dut\x12=\n\x10inventory_server\x18\x04 \x01(\x0b\x32#.chromiumos.test.lab.api.IpEndpoint\x12\x14\n\x0c\x61rtifact_dir\x18\x05 \x01(\t\"\\\n\x1a\x43rosToolRunnerTestResponse\x12>\n\x11test_case_results\x18\x01 \x03(\x0b\x32#.chromiumos.test.api.TestCaseResult\"l\n\x1f\x43rosToolRunnerTestFinderRequest\x12\x33\n\x0btest_suites\x18\x01 \x03(\x0b\x32\x1e.chromiumos.test.api.TestSuite\x12\x14\n\x0c\x61rtifact_dir\x18\x02 \x01(\t\"W\n CrosToolRunnerTestFinderResponse\x12\x33\n\x0btest_suites\x18\x01 \x03(\x0b\x32\x1e.chromiumos.test.api.TestSuiteB/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
+  serialized_pb=b'\n.chromiumos/test/api/cros_tool_runner_cli.proto\x12\x13\x63hromiumos.test.api\x1a)chromiumos/test/api/provision_state.proto\x1a,chromiumos/test/api/cros_provision_cli.proto\x1a*chromiumos/test/api/test_case_result.proto\x1a$chromiumos/test/api/test_suite.proto\x1a!chromiumos/test/lab/api/dut.proto\x1a)chromiumos/test/lab/api/ip_endpoint.proto\"\xd6\x02\n\x1e\x43rosToolRunnerProvisionRequest\x12K\n\x07\x64\x65vices\x18\x01 \x03(\x0b\x32:.chromiumos.test.api.CrosToolRunnerProvisionRequest.Device\x12=\n\x10inventory_server\x18\x02 \x01(\x0b\x32#.chromiumos.test.lab.api.IpEndpoint\x12\x14\n\x0c\x61rtifact_dir\x18\x03 \x01(\t\x1a\x91\x01\n\x06\x44\x65vice\x12)\n\x03\x64ut\x18\x01 \x01(\x0b\x32\x1c.chromiumos.test.lab.api.Dut\x12<\n\x0fprovision_state\x18\x02 \x01(\x0b\x32#.chromiumos.test.api.ProvisionState\x12\x1e\n\x16\x63ontainer_metadata_key\x18\x03 \x01(\t\"`\n\x1f\x43rosToolRunnerProvisionResponse\x12=\n\tresponses\x18\x01 \x03(\x0b\x32*.chromiumos.test.api.CrosProvisionResponse\"\x95\x03\n\x19\x43rosToolRunnerTestRequest\x12\x33\n\x0btest_suites\x18\x01 \x03(\x0b\x32\x1e.chromiumos.test.api.TestSuite\x12J\n\x0bprimary_dut\x18\x02 \x01(\x0b\x32\x35.chromiumos.test.api.CrosToolRunnerTestRequest.Device\x12M\n\x0e\x63ompanion_duts\x18\x03 \x03(\x0b\x32\x35.chromiumos.test.api.CrosToolRunnerTestRequest.Device\x12=\n\x10inventory_server\x18\x04 \x01(\x0b\x32#.chromiumos.test.lab.api.IpEndpoint\x12\x14\n\x0c\x61rtifact_dir\x18\x05 \x01(\t\x1aS\n\x06\x44\x65vice\x12)\n\x03\x64ut\x18\x01 \x01(\x0b\x32\x1c.chromiumos.test.lab.api.Dut\x12\x1e\n\x16\x63ontainer_metadata_key\x18\x02 \x01(\t\"\\\n\x1a\x43rosToolRunnerTestResponse\x12>\n\x11test_case_results\x18\x01 \x03(\x0b\x32#.chromiumos.test.api.TestCaseResult\"\x8c\x01\n\x1f\x43rosToolRunnerTestFinderRequest\x12\x33\n\x0btest_suites\x18\x01 \x03(\x0b\x32\x1e.chromiumos.test.api.TestSuite\x12\x14\n\x0c\x61rtifact_dir\x18\x02 \x01(\t\x12\x1e\n\x16\x63ontainer_metadata_key\x18\x03 \x01(\t\"W\n CrosToolRunnerTestFinderResponse\x12\x33\n\x0btest_suites\x18\x01 \x03(\x0b\x32\x1e.chromiumos.test.api.TestSuiteB/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
   ,
   dependencies=[chromiumos_dot_test_dot_api_dot_provision__state__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_cros__provision__cli__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_test__case__result__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_test__suite__pb2.DESCRIPTOR,chromiumos_dot_test_dot_lab_dot_api_dot_dut__pb2.DESCRIPTOR,chromiumos_dot_test_dot_lab_dot_api_dot_ip__endpoint__pb2.DESCRIPTOR,])
 
@@ -52,6 +52,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='container_metadata_key', full_name='chromiumos.test.api.CrosToolRunnerProvisionRequest.Device.container_metadata_key', index=2,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -64,8 +71,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=517,
-  serialized_end=630,
+  serialized_start=518,
+  serialized_end=663,
 )
 
 _CROSTOOLRUNNERPROVISIONREQUEST = _descriptor.Descriptor(
@@ -109,7 +116,7 @@
   oneofs=[
   ],
   serialized_start=321,
-  serialized_end=630,
+  serialized_end=663,
 )
 
 
@@ -139,11 +146,48 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=632,
-  serialized_end=728,
+  serialized_start=665,
+  serialized_end=761,
 )
 
 
+_CROSTOOLRUNNERTESTREQUEST_DEVICE = _descriptor.Descriptor(
+  name='Device',
+  full_name='chromiumos.test.api.CrosToolRunnerTestRequest.Device',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='dut', full_name='chromiumos.test.api.CrosToolRunnerTestRequest.Device.dut', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='container_metadata_key', full_name='chromiumos.test.api.CrosToolRunnerTestRequest.Device.container_metadata_key', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1086,
+  serialized_end=1169,
+)
+
 _CROSTOOLRUNNERTESTREQUEST = _descriptor.Descriptor(
   name='CrosToolRunnerTestRequest',
   full_name='chromiumos.test.api.CrosToolRunnerTestRequest',
@@ -189,7 +233,7 @@
   ],
   extensions=[
   ],
-  nested_types=[],
+  nested_types=[_CROSTOOLRUNNERTESTREQUEST_DEVICE, ],
   enum_types=[
   ],
   serialized_options=None,
@@ -198,8 +242,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=731,
-  serialized_end=1001,
+  serialized_start=764,
+  serialized_end=1169,
 )
 
 
@@ -229,8 +273,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1003,
-  serialized_end=1095,
+  serialized_start=1171,
+  serialized_end=1263,
 )
 
 
@@ -255,6 +299,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='container_metadata_key', full_name='chromiumos.test.api.CrosToolRunnerTestFinderRequest.container_metadata_key', index=2,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -267,8 +318,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1097,
-  serialized_end=1205,
+  serialized_start=1266,
+  serialized_end=1406,
 )
 
 
@@ -298,8 +349,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1207,
-  serialized_end=1294,
+  serialized_start=1408,
+  serialized_end=1495,
 )
 
 _CROSTOOLRUNNERPROVISIONREQUEST_DEVICE.fields_by_name['dut'].message_type = chromiumos_dot_test_dot_lab_dot_api_dot_dut__pb2._DUT
@@ -308,9 +359,11 @@
 _CROSTOOLRUNNERPROVISIONREQUEST.fields_by_name['devices'].message_type = _CROSTOOLRUNNERPROVISIONREQUEST_DEVICE
 _CROSTOOLRUNNERPROVISIONREQUEST.fields_by_name['inventory_server'].message_type = chromiumos_dot_test_dot_lab_dot_api_dot_ip__endpoint__pb2._IPENDPOINT
 _CROSTOOLRUNNERPROVISIONRESPONSE.fields_by_name['responses'].message_type = chromiumos_dot_test_dot_api_dot_cros__provision__cli__pb2._CROSPROVISIONRESPONSE
+_CROSTOOLRUNNERTESTREQUEST_DEVICE.fields_by_name['dut'].message_type = chromiumos_dot_test_dot_lab_dot_api_dot_dut__pb2._DUT
+_CROSTOOLRUNNERTESTREQUEST_DEVICE.containing_type = _CROSTOOLRUNNERTESTREQUEST
 _CROSTOOLRUNNERTESTREQUEST.fields_by_name['test_suites'].message_type = chromiumos_dot_test_dot_api_dot_test__suite__pb2._TESTSUITE
-_CROSTOOLRUNNERTESTREQUEST.fields_by_name['primary_dut'].message_type = chromiumos_dot_test_dot_lab_dot_api_dot_dut__pb2._DUT
-_CROSTOOLRUNNERTESTREQUEST.fields_by_name['companion_duts'].message_type = chromiumos_dot_test_dot_lab_dot_api_dot_dut__pb2._DUT
+_CROSTOOLRUNNERTESTREQUEST.fields_by_name['primary_dut'].message_type = _CROSTOOLRUNNERTESTREQUEST_DEVICE
+_CROSTOOLRUNNERTESTREQUEST.fields_by_name['companion_duts'].message_type = _CROSTOOLRUNNERTESTREQUEST_DEVICE
 _CROSTOOLRUNNERTESTREQUEST.fields_by_name['inventory_server'].message_type = chromiumos_dot_test_dot_lab_dot_api_dot_ip__endpoint__pb2._IPENDPOINT
 _CROSTOOLRUNNERTESTRESPONSE.fields_by_name['test_case_results'].message_type = chromiumos_dot_test_dot_api_dot_test__case__result__pb2._TESTCASERESULT
 _CROSTOOLRUNNERTESTFINDERREQUEST.fields_by_name['test_suites'].message_type = chromiumos_dot_test_dot_api_dot_test__suite__pb2._TESTSUITE
@@ -346,11 +399,19 @@
 _sym_db.RegisterMessage(CrosToolRunnerProvisionResponse)
 
 CrosToolRunnerTestRequest = _reflection.GeneratedProtocolMessageType('CrosToolRunnerTestRequest', (_message.Message,), {
+
+  'Device' : _reflection.GeneratedProtocolMessageType('Device', (_message.Message,), {
+    'DESCRIPTOR' : _CROSTOOLRUNNERTESTREQUEST_DEVICE,
+    '__module__' : 'chromiumos.test.api.cros_tool_runner_cli_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.CrosToolRunnerTestRequest.Device)
+    })
+  ,
   'DESCRIPTOR' : _CROSTOOLRUNNERTESTREQUEST,
   '__module__' : 'chromiumos.test.api.cros_tool_runner_cli_pb2'
   # @@protoc_insertion_point(class_scope:chromiumos.test.api.CrosToolRunnerTestRequest)
   })
 _sym_db.RegisterMessage(CrosToolRunnerTestRequest)
+_sym_db.RegisterMessage(CrosToolRunnerTestRequest.Device)
 
 CrosToolRunnerTestResponse = _reflection.GeneratedProtocolMessageType('CrosToolRunnerTestResponse', (_message.Message,), {
   'DESCRIPTOR' : _CROSTOOLRUNNERTESTRESPONSE,
diff --git a/api/gen_sdk/chromiumos/test/api/dut_attribute_pb2.py b/api/gen_sdk/chromiumos/test/api/dut_attribute_pb2.py
index c3ffe8a..590fcc8 100644
--- a/api/gen_sdk/chromiumos/test/api/dut_attribute_pb2.py
+++ b/api/gen_sdk/chromiumos/test/api/dut_attribute_pb2.py
@@ -19,7 +19,7 @@
   package='chromiumos.test.api',
   syntax='proto3',
   serialized_options=b'Z-go.chromium.org/chromiumos/config/go/test/api',
-  serialized_pb=b'\n\'chromiumos/test/api/dut_attribute.proto\x12\x13\x63hromiumos.test.api\x1a)chromiumos/test/api/provision_state.proto\"\x8b\x04\n\x0c\x44utAttribute\x12\x30\n\x02id\x18\x01 \x01(\x0b\x32$.chromiumos.test.api.DutAttribute.Id\x12\x0f\n\x07\x61liases\x18\x02 \x03(\t\x12P\n\x12\x66lat_config_source\x18\x03 \x01(\x0b\x32\x32.chromiumos.test.api.DutAttribute.FlatConfigSourceH\x00\x12\x43\n\x0bhwid_source\x18\x04 \x01(\x0b\x32,.chromiumos.test.api.DutAttribute.HwidSourceH\x00\x12\x16\n\x0e\x61llowed_values\x18\x05 \x03(\t\x12\x16\n\x0e\x65xclude_values\x18\x06 \x03(\t\x1a\x13\n\x02Id\x12\r\n\x05value\x18\x01 \x01(\t\x1a\x19\n\tFieldSpec\x12\x0c\n\x04path\x18\x01 \x01(\t\x1aO\n\x10\x46latConfigSource\x12;\n\x06\x66ields\x18\x01 \x03(\x0b\x32+.chromiumos.test.api.DutAttribute.FieldSpec\x1a\x61\n\nHwidSource\x12\x16\n\x0e\x63omponent_type\x18\x01 \x01(\t\x12;\n\x06\x66ields\x18\x02 \x03(\x0b\x32+.chromiumos.test.api.DutAttribute.FieldSpecB\r\n\x0b\x64\x61ta_source\"M\n\x10\x44utAttributeList\x12\x39\n\x0e\x64ut_attributes\x18\x01 \x03(\x0b\x32!.chromiumos.test.api.DutAttribute\"Z\n\x0c\x44utCriterion\x12:\n\x0c\x61ttribute_id\x18\x01 \x01(\x0b\x32$.chromiumos.test.api.DutAttribute.Id\x12\x0e\n\x06values\x18\x02 \x03(\t\"\x80\x01\n\tDutTarget\x12\x33\n\x08\x63riteria\x18\x01 \x03(\x0b\x32!.chromiumos.test.api.DutCriterion\x12>\n\x10provision_config\x18\x02 \x01(\x0b\x32$.chromiumos.test.api.ProvisionConfigB/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
+  serialized_pb=b'\n\'chromiumos/test/api/dut_attribute.proto\x12\x13\x63hromiumos.test.api\x1a)chromiumos/test/api/provision_state.proto\"\xdb\x04\n\x0c\x44utAttribute\x12\x30\n\x02id\x18\x01 \x01(\x0b\x32$.chromiumos.test.api.DutAttribute.Id\x12\x0f\n\x07\x61liases\x18\x02 \x03(\t\x12P\n\x12\x66lat_config_source\x18\x03 \x01(\x0b\x32\x32.chromiumos.test.api.DutAttribute.FlatConfigSourceH\x00\x12\x43\n\x0bhwid_source\x18\x04 \x01(\x0b\x32,.chromiumos.test.api.DutAttribute.HwidSourceH\x00\x12\x41\n\ntle_source\x18\x07 \x01(\x0b\x32+.chromiumos.test.api.DutAttribute.TleSourceH\x00\x12\x16\n\x0e\x61llowed_values\x18\x05 \x03(\t\x12\x16\n\x0e\x65xclude_values\x18\x06 \x03(\t\x1a\x13\n\x02Id\x12\r\n\x05value\x18\x01 \x01(\t\x1a\x19\n\tFieldSpec\x12\x0c\n\x04path\x18\x01 \x01(\t\x1aO\n\x10\x46latConfigSource\x12;\n\x06\x66ields\x18\x01 \x03(\x0b\x32+.chromiumos.test.api.DutAttribute.FieldSpec\x1a\x61\n\nHwidSource\x12\x16\n\x0e\x63omponent_type\x18\x01 \x01(\t\x12;\n\x06\x66ields\x18\x02 \x03(\x0b\x32+.chromiumos.test.api.DutAttribute.FieldSpec\x1a\x0b\n\tTleSourceB\r\n\x0b\x64\x61ta_source\"M\n\x10\x44utAttributeList\x12\x39\n\x0e\x64ut_attributes\x18\x01 \x03(\x0b\x32!.chromiumos.test.api.DutAttribute\"Z\n\x0c\x44utCriterion\x12:\n\x0c\x61ttribute_id\x18\x01 \x01(\x0b\x32$.chromiumos.test.api.DutAttribute.Id\x12\x0e\n\x06values\x18\x02 \x03(\t\"\x80\x01\n\tDutTarget\x12\x33\n\x08\x63riteria\x18\x01 \x03(\x0b\x32!.chromiumos.test.api.DutCriterion\x12>\n\x10provision_config\x18\x02 \x01(\x0b\x32$.chromiumos.test.api.ProvisionConfigB/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
   ,
   dependencies=[chromiumos_dot_test_dot_api_dot_provision__state__pb2.DESCRIPTOR,])
 
@@ -52,8 +52,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=390,
-  serialized_end=409,
+  serialized_start=457,
+  serialized_end=476,
 )
 
 _DUTATTRIBUTE_FIELDSPEC = _descriptor.Descriptor(
@@ -82,8 +82,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=411,
-  serialized_end=436,
+  serialized_start=478,
+  serialized_end=503,
 )
 
 _DUTATTRIBUTE_FLATCONFIGSOURCE = _descriptor.Descriptor(
@@ -112,8 +112,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=438,
-  serialized_end=517,
+  serialized_start=505,
+  serialized_end=584,
 )
 
 _DUTATTRIBUTE_HWIDSOURCE = _descriptor.Descriptor(
@@ -149,8 +149,31 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=519,
-  serialized_end=616,
+  serialized_start=586,
+  serialized_end=683,
+)
+
+_DUTATTRIBUTE_TLESOURCE = _descriptor.Descriptor(
+  name='TleSource',
+  full_name='chromiumos.test.api.DutAttribute.TleSource',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=685,
+  serialized_end=696,
 )
 
 _DUTATTRIBUTE = _descriptor.Descriptor(
@@ -189,14 +212,21 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='allowed_values', full_name='chromiumos.test.api.DutAttribute.allowed_values', index=4,
+      name='tle_source', full_name='chromiumos.test.api.DutAttribute.tle_source', index=4,
+      number=7, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='allowed_values', full_name='chromiumos.test.api.DutAttribute.allowed_values', index=5,
       number=5, type=9, cpp_type=9, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='exclude_values', full_name='chromiumos.test.api.DutAttribute.exclude_values', index=5,
+      name='exclude_values', full_name='chromiumos.test.api.DutAttribute.exclude_values', index=6,
       number=6, type=9, cpp_type=9, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
@@ -205,7 +235,7 @@
   ],
   extensions=[
   ],
-  nested_types=[_DUTATTRIBUTE_ID, _DUTATTRIBUTE_FIELDSPEC, _DUTATTRIBUTE_FLATCONFIGSOURCE, _DUTATTRIBUTE_HWIDSOURCE, ],
+  nested_types=[_DUTATTRIBUTE_ID, _DUTATTRIBUTE_FIELDSPEC, _DUTATTRIBUTE_FLATCONFIGSOURCE, _DUTATTRIBUTE_HWIDSOURCE, _DUTATTRIBUTE_TLESOURCE, ],
   enum_types=[
   ],
   serialized_options=None,
@@ -218,7 +248,7 @@
       index=0, containing_type=None, fields=[]),
   ],
   serialized_start=108,
-  serialized_end=631,
+  serialized_end=711,
 )
 
 
@@ -248,8 +278,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=633,
-  serialized_end=710,
+  serialized_start=713,
+  serialized_end=790,
 )
 
 
@@ -286,8 +316,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=712,
-  serialized_end=802,
+  serialized_start=792,
+  serialized_end=882,
 )
 
 
@@ -324,8 +354,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=805,
-  serialized_end=933,
+  serialized_start=885,
+  serialized_end=1013,
 )
 
 _DUTATTRIBUTE_ID.containing_type = _DUTATTRIBUTE
@@ -334,15 +364,20 @@
 _DUTATTRIBUTE_FLATCONFIGSOURCE.containing_type = _DUTATTRIBUTE
 _DUTATTRIBUTE_HWIDSOURCE.fields_by_name['fields'].message_type = _DUTATTRIBUTE_FIELDSPEC
 _DUTATTRIBUTE_HWIDSOURCE.containing_type = _DUTATTRIBUTE
+_DUTATTRIBUTE_TLESOURCE.containing_type = _DUTATTRIBUTE
 _DUTATTRIBUTE.fields_by_name['id'].message_type = _DUTATTRIBUTE_ID
 _DUTATTRIBUTE.fields_by_name['flat_config_source'].message_type = _DUTATTRIBUTE_FLATCONFIGSOURCE
 _DUTATTRIBUTE.fields_by_name['hwid_source'].message_type = _DUTATTRIBUTE_HWIDSOURCE
+_DUTATTRIBUTE.fields_by_name['tle_source'].message_type = _DUTATTRIBUTE_TLESOURCE
 _DUTATTRIBUTE.oneofs_by_name['data_source'].fields.append(
   _DUTATTRIBUTE.fields_by_name['flat_config_source'])
 _DUTATTRIBUTE.fields_by_name['flat_config_source'].containing_oneof = _DUTATTRIBUTE.oneofs_by_name['data_source']
 _DUTATTRIBUTE.oneofs_by_name['data_source'].fields.append(
   _DUTATTRIBUTE.fields_by_name['hwid_source'])
 _DUTATTRIBUTE.fields_by_name['hwid_source'].containing_oneof = _DUTATTRIBUTE.oneofs_by_name['data_source']
+_DUTATTRIBUTE.oneofs_by_name['data_source'].fields.append(
+  _DUTATTRIBUTE.fields_by_name['tle_source'])
+_DUTATTRIBUTE.fields_by_name['tle_source'].containing_oneof = _DUTATTRIBUTE.oneofs_by_name['data_source']
 _DUTATTRIBUTELIST.fields_by_name['dut_attributes'].message_type = _DUTATTRIBUTE
 _DUTCRITERION.fields_by_name['attribute_id'].message_type = _DUTATTRIBUTE_ID
 _DUTTARGET.fields_by_name['criteria'].message_type = _DUTCRITERION
@@ -382,6 +417,13 @@
     # @@protoc_insertion_point(class_scope:chromiumos.test.api.DutAttribute.HwidSource)
     })
   ,
+
+  'TleSource' : _reflection.GeneratedProtocolMessageType('TleSource', (_message.Message,), {
+    'DESCRIPTOR' : _DUTATTRIBUTE_TLESOURCE,
+    '__module__' : 'chromiumos.test.api.dut_attribute_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.DutAttribute.TleSource)
+    })
+  ,
   'DESCRIPTOR' : _DUTATTRIBUTE,
   '__module__' : 'chromiumos.test.api.dut_attribute_pb2'
   # @@protoc_insertion_point(class_scope:chromiumos.test.api.DutAttribute)
@@ -391,6 +433,7 @@
 _sym_db.RegisterMessage(DutAttribute.FieldSpec)
 _sym_db.RegisterMessage(DutAttribute.FlatConfigSource)
 _sym_db.RegisterMessage(DutAttribute.HwidSource)
+_sym_db.RegisterMessage(DutAttribute.TleSource)
 
 DutAttributeList = _reflection.GeneratedProtocolMessageType('DutAttributeList', (_message.Message,), {
   'DESCRIPTOR' : _DUTATTRIBUTELIST,
diff --git a/api/gen_sdk/chromiumos/test/api/dut_service_pb2.py b/api/gen_sdk/chromiumos/test/api/dut_service_pb2.py
index b5b128b..7fcfa31 100644
--- a/api/gen_sdk/chromiumos/test/api/dut_service_pb2.py
+++ b/api/gen_sdk/chromiumos/test/api/dut_service_pb2.py
@@ -21,7 +21,7 @@
   package='chromiumos.test.api',
   syntax='proto3',
   serialized_options=b'Z-go.chromium.org/chromiumos/config/go/test/api',
-  serialized_pb=b'\n%chromiumos/test/api/dut_service.proto\x12\x13\x63hromiumos.test.api\x1a,chromiumos/config/api/device_config_id.proto\x1a\'chromiumos/longrunning/operations.proto\"\xaa\x01\n\x12\x45xecCommandRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07\x63ommand\x18\x02 \x01(\t\x12\x0c\n\x04\x61rgs\x18\x03 \x03(\t\x12\r\n\x05stdin\x18\x04 \x01(\x0c\x12+\n\x06stdout\x18\x05 \x01(\x0e\x32\x1b.chromiumos.test.api.Output\x12+\n\x06stderr\x18\x06 \x01(\x0e\x32\x1b.chromiumos.test.api.Output\"\xd1\x01\n\x13\x45xecCommandResponse\x12\x44\n\texit_info\x18\x01 \x01(\x0b\x32\x31.chromiumos.test.api.ExecCommandResponse.ExitInfo\x12\x0e\n\x06stdout\x18\x02 \x01(\x0c\x12\x0e\n\x06stderr\x18\x03 \x01(\x0c\x1aT\n\x08\x45xitInfo\x12\x0e\n\x06status\x18\x01 \x01(\x05\x12\x10\n\x08signaled\x18\x02 \x01(\x08\x12\x0f\n\x07started\x18\x03 \x01(\x08\x12\x15\n\rerror_message\x18\x04 \x01(\t\"/\n\x13\x46\x65tchCrashesRequest\x12\x12\n\nfetch_core\x18\x02 \x01(\x08J\x04\x08\x01\x10\x02\"\xa1\x01\n\x14\x46\x65tchCrashesResponse\x12\x10\n\x08\x63rash_id\x18\x01 \x01(\x03\x12/\n\x05\x63rash\x18\x02 \x01(\x0b\x32\x1e.chromiumos.test.api.CrashInfoH\x00\x12.\n\x04\x62lob\x18\x03 \x01(\x0b\x32\x1e.chromiumos.test.api.CrashBlobH\x00\x12\x0e\n\x04\x63ore\x18\x04 \x01(\x0cH\x00\x42\x06\n\x04\x64\x61ta\"\xb3\x01\n\tCrashInfo\x12\x11\n\texec_name\x18\x01 \x01(\t\x12\x0c\n\x04prod\x18\x02 \x01(\t\x12\x0b\n\x03ver\x18\x03 \x01(\t\x12\x0b\n\x03sig\x18\x04 \x01(\t\x12$\n\x1cin_progress_integration_test\x18\x05 \x01(\t\x12\x11\n\tcollector\x18\x06 \x01(\t\x12\x32\n\x06\x66ields\x18\x07 \x03(\x0b\x32\".chromiumos.test.api.CrashMetadata\"*\n\rCrashMetadata\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x0c\n\x04text\x18\x02 \x01(\t\"8\n\tCrashBlob\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x0c\n\x04\x62lob\x18\x02 \x01(\x0c\x12\x10\n\x08\x66ilename\x18\x03 \x01(\t\"\x1e\n\x0eRestartRequest\x12\x0c\n\x04\x61rgs\x18\x01 \x03(\t\"!\n\x0fRestartResponse\x12\x0e\n\x06output\x18\x01 \x01(\t\"\x11\n\x0fRestartMetadata\"\x1d\n\x1b\x44\x65tectDeviceConfigIdRequest\"\xc1\x02\n\x1c\x44\x65tectDeviceConfigIdResponse\x12L\n\x07success\x18\x01 \x01(\x0b\x32\x39.chromiumos.test.api.DetectDeviceConfigIdResponse.SuccessH\x00\x12L\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32\x39.chromiumos.test.api.DetectDeviceConfigIdResponse.FailureH\x00\x1aY\n\x07Success\x12N\n\x14\x64\x65tected_scan_config\x18\x01 \x01(\x0b\x32\x30.chromiumos.config.api.DeviceConfigId.ScanConfig\x1a \n\x07\x46\x61ilure\x12\x15\n\rerror_message\x18\x01 \x01(\tB\x08\n\x06result*,\n\x06Output\x12\x0f\n\x0bOUTPUT_PIPE\x10\x00\x12\x11\n\rOUTPUT_STDOUT\x10\x01\x32\xd0\x03\n\nDutService\x12\x62\n\x0b\x45xecCommand\x12\'.chromiumos.test.api.ExecCommandRequest\x1a(.chromiumos.test.api.ExecCommandResponse0\x01\x12\x65\n\x0c\x46\x65tchCrashes\x12(.chromiumos.test.api.FetchCrashesRequest\x1a).chromiumos.test.api.FetchCrashesResponse0\x01\x12x\n\x07Restart\x12#.chromiumos.test.api.RestartRequest\x1a!.chromiumos.longrunning.Operation\"%\xd2\x41\"\n\x0fRestartResponse\x12\x0fRestartMetadata\x12}\n\x14\x44\x65tectDeviceConfigId\x12\x30.chromiumos.test.api.DetectDeviceConfigIdRequest\x1a\x31.chromiumos.test.api.DetectDeviceConfigIdResponse0\x01\x42/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
+  serialized_pb=b'\n%chromiumos/test/api/dut_service.proto\x12\x13\x63hromiumos.test.api\x1a,chromiumos/config/api/device_config_id.proto\x1a\'chromiumos/longrunning/operations.proto\"\xaa\x01\n\x12\x45xecCommandRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07\x63ommand\x18\x02 \x01(\t\x12\x0c\n\x04\x61rgs\x18\x03 \x03(\t\x12\r\n\x05stdin\x18\x04 \x01(\x0c\x12+\n\x06stdout\x18\x05 \x01(\x0e\x32\x1b.chromiumos.test.api.Output\x12+\n\x06stderr\x18\x06 \x01(\x0e\x32\x1b.chromiumos.test.api.Output\"\xd1\x01\n\x13\x45xecCommandResponse\x12\x44\n\texit_info\x18\x01 \x01(\x0b\x32\x31.chromiumos.test.api.ExecCommandResponse.ExitInfo\x12\x0e\n\x06stdout\x18\x02 \x01(\x0c\x12\x0e\n\x06stderr\x18\x03 \x01(\x0c\x1aT\n\x08\x45xitInfo\x12\x0e\n\x06status\x18\x01 \x01(\x05\x12\x10\n\x08signaled\x18\x02 \x01(\x08\x12\x0f\n\x07started\x18\x03 \x01(\x08\x12\x15\n\rerror_message\x18\x04 \x01(\t\"/\n\x13\x46\x65tchCrashesRequest\x12\x12\n\nfetch_core\x18\x02 \x01(\x08J\x04\x08\x01\x10\x02\"\xa1\x01\n\x14\x46\x65tchCrashesResponse\x12\x10\n\x08\x63rash_id\x18\x01 \x01(\x03\x12/\n\x05\x63rash\x18\x02 \x01(\x0b\x32\x1e.chromiumos.test.api.CrashInfoH\x00\x12.\n\x04\x62lob\x18\x03 \x01(\x0b\x32\x1e.chromiumos.test.api.CrashBlobH\x00\x12\x0e\n\x04\x63ore\x18\x04 \x01(\x0cH\x00\x42\x06\n\x04\x64\x61ta\"\xb3\x01\n\tCrashInfo\x12\x11\n\texec_name\x18\x01 \x01(\t\x12\x0c\n\x04prod\x18\x02 \x01(\t\x12\x0b\n\x03ver\x18\x03 \x01(\t\x12\x0b\n\x03sig\x18\x04 \x01(\t\x12$\n\x1cin_progress_integration_test\x18\x05 \x01(\t\x12\x11\n\tcollector\x18\x06 \x01(\t\x12\x32\n\x06\x66ields\x18\x07 \x03(\x0b\x32\".chromiumos.test.api.CrashMetadata\"*\n\rCrashMetadata\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x0c\n\x04text\x18\x02 \x01(\t\"8\n\tCrashBlob\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x0c\n\x04\x62lob\x18\x02 \x01(\x0c\x12\x10\n\x08\x66ilename\x18\x03 \x01(\t\"\x1e\n\x0eRestartRequest\x12\x0c\n\x04\x61rgs\x18\x01 \x03(\t\"!\n\x0fRestartResponse\x12\x0e\n\x06output\x18\x01 \x01(\t\"\x11\n\x0fRestartMetadata\"\x8e\x04\n\x0c\x43\x61\x63heRequest\x12;\n\x04\x66ile\x18\x01 \x01(\x0b\x32+.chromiumos.test.api.CacheRequest.LocalFileH\x00\x12\x36\n\x04pipe\x18\x02 \x01(\x0b\x32&.chromiumos.test.api.CacheRequest.PipeH\x00\x12;\n\x07gs_file\x18\x03 \x01(\x0b\x32(.chromiumos.test.api.CacheRequest.GSFileH\x01\x12\x42\n\x0bgs_zip_file\x18\x04 \x01(\x0b\x32+.chromiumos.test.api.CacheRequest.GSZipFileH\x01\x12\x42\n\x0bgs_tar_file\x18\x05 \x01(\x0b\x32+.chromiumos.test.api.CacheRequest.GSTARFileH\x01\x1a\x19\n\tLocalFile\x12\x0c\n\x04path\x18\x01 \x01(\t\x1a\x18\n\x04Pipe\x12\x10\n\x08\x63ommands\x18\x01 \x01(\t\x1a\x1d\n\x06GSFile\x12\x13\n\x0bsource_path\x18\x01 \x01(\t\x1a \n\tGSZipFile\x12\x13\n\x0bsource_path\x18\x01 \x01(\t\x1a\x35\n\tGSTARFile\x12\x13\n\x0bsource_path\x18\x01 \x01(\t\x12\x13\n\x0bsource_file\x18\x02 \x01(\tB\r\n\x0b\x64\x65stinationB\x08\n\x06source\"\xc4\x01\n\rCacheResponse\x12=\n\x07success\x18\x01 \x01(\x0b\x32*.chromiumos.test.api.CacheResponse.SuccessH\x00\x12=\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32*.chromiumos.test.api.CacheResponse.FailureH\x00\x1a\t\n\x07Success\x1a \n\x07\x46\x61ilure\x12\x15\n\rerror_message\x18\x01 \x01(\tB\x08\n\x06result\"\x0f\n\rCacheMetadata\"\x17\n\x15\x46orceReconnectRequest\"\xdf\x01\n\x16\x46orceReconnectResponse\x12\x46\n\x07success\x18\x01 \x01(\x0b\x32\x33.chromiumos.test.api.ForceReconnectResponse.SuccessH\x00\x12\x46\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32\x33.chromiumos.test.api.ForceReconnectResponse.FailureH\x00\x1a\t\n\x07Success\x1a \n\x07\x46\x61ilure\x12\x15\n\rerror_message\x18\x01 \x01(\tB\x08\n\x06result\"\x18\n\x16\x46orceReconnectMetadata\"\x1d\n\x1b\x44\x65tectDeviceConfigIdRequest\"\xc1\x02\n\x1c\x44\x65tectDeviceConfigIdResponse\x12L\n\x07success\x18\x01 \x01(\x0b\x32\x39.chromiumos.test.api.DetectDeviceConfigIdResponse.SuccessH\x00\x12L\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32\x39.chromiumos.test.api.DetectDeviceConfigIdResponse.FailureH\x00\x1aY\n\x07Success\x12N\n\x14\x64\x65tected_scan_config\x18\x01 \x01(\x0b\x32\x30.chromiumos.config.api.DeviceConfigId.ScanConfig\x1a \n\x07\x46\x61ilure\x12\x15\n\rerror_message\x18\x01 \x01(\tB\x08\n\x06result*,\n\x06Output\x12\x0f\n\x0bOUTPUT_PIPE\x10\x00\x12\x11\n\rOUTPUT_STDOUT\x10\x01\x32\xd9\x05\n\nDutService\x12\x62\n\x0b\x45xecCommand\x12\'.chromiumos.test.api.ExecCommandRequest\x1a(.chromiumos.test.api.ExecCommandResponse0\x01\x12\x65\n\x0c\x46\x65tchCrashes\x12(.chromiumos.test.api.FetchCrashesRequest\x1a).chromiumos.test.api.FetchCrashesResponse0\x01\x12x\n\x07Restart\x12#.chromiumos.test.api.RestartRequest\x1a!.chromiumos.longrunning.Operation\"%\xd2\x41\"\n\x0fRestartResponse\x12\x0fRestartMetadata\x12}\n\x14\x44\x65tectDeviceConfigId\x12\x30.chromiumos.test.api.DetectDeviceConfigIdRequest\x1a\x31.chromiumos.test.api.DetectDeviceConfigIdResponse0\x01\x12p\n\x05\x43\x61\x63he\x12!.chromiumos.test.api.CacheRequest\x1a!.chromiumos.longrunning.Operation\"!\xd2\x41\x1e\n\rCacheResponse\x12\rCacheMetadata\x12\x94\x01\n\x0e\x46orceReconnect\x12*.chromiumos.test.api.ForceReconnectRequest\x1a!.chromiumos.longrunning.Operation\"3\xd2\x41\x30\n\x16\x46orceReconnectResponse\x12\x16\x46orceReconnectMetadataB/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
   ,
   dependencies=[chromiumos_dot_config_dot_api_dot_device__config__id__pb2.DESCRIPTOR,chromiumos_dot_longrunning_dot_operations__pb2.DESCRIPTOR,])
 
@@ -42,8 +42,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1472,
-  serialized_end=1516,
+  serialized_start=2494,
+  serialized_end=2538,
 )
 _sym_db.RegisterEnumDescriptor(_OUTPUT)
 
@@ -543,6 +543,488 @@
 )
 
 
+_CACHEREQUEST_LOCALFILE = _descriptor.Descriptor(
+  name='LocalFile',
+  full_name='chromiumos.test.api.CacheRequest.LocalFile',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='path', full_name='chromiumos.test.api.CacheRequest.LocalFile.path', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1448,
+  serialized_end=1473,
+)
+
+_CACHEREQUEST_PIPE = _descriptor.Descriptor(
+  name='Pipe',
+  full_name='chromiumos.test.api.CacheRequest.Pipe',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='commands', full_name='chromiumos.test.api.CacheRequest.Pipe.commands', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1475,
+  serialized_end=1499,
+)
+
+_CACHEREQUEST_GSFILE = _descriptor.Descriptor(
+  name='GSFile',
+  full_name='chromiumos.test.api.CacheRequest.GSFile',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='source_path', full_name='chromiumos.test.api.CacheRequest.GSFile.source_path', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1501,
+  serialized_end=1530,
+)
+
+_CACHEREQUEST_GSZIPFILE = _descriptor.Descriptor(
+  name='GSZipFile',
+  full_name='chromiumos.test.api.CacheRequest.GSZipFile',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='source_path', full_name='chromiumos.test.api.CacheRequest.GSZipFile.source_path', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1532,
+  serialized_end=1564,
+)
+
+_CACHEREQUEST_GSTARFILE = _descriptor.Descriptor(
+  name='GSTARFile',
+  full_name='chromiumos.test.api.CacheRequest.GSTARFile',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='source_path', full_name='chromiumos.test.api.CacheRequest.GSTARFile.source_path', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='source_file', full_name='chromiumos.test.api.CacheRequest.GSTARFile.source_file', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1566,
+  serialized_end=1619,
+)
+
+_CACHEREQUEST = _descriptor.Descriptor(
+  name='CacheRequest',
+  full_name='chromiumos.test.api.CacheRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='file', full_name='chromiumos.test.api.CacheRequest.file', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='pipe', full_name='chromiumos.test.api.CacheRequest.pipe', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='gs_file', full_name='chromiumos.test.api.CacheRequest.gs_file', index=2,
+      number=3, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='gs_zip_file', full_name='chromiumos.test.api.CacheRequest.gs_zip_file', index=3,
+      number=4, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='gs_tar_file', full_name='chromiumos.test.api.CacheRequest.gs_tar_file', index=4,
+      number=5, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[_CACHEREQUEST_LOCALFILE, _CACHEREQUEST_PIPE, _CACHEREQUEST_GSFILE, _CACHEREQUEST_GSZIPFILE, _CACHEREQUEST_GSTARFILE, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+    _descriptor.OneofDescriptor(
+      name='destination', full_name='chromiumos.test.api.CacheRequest.destination',
+      index=0, containing_type=None, fields=[]),
+    _descriptor.OneofDescriptor(
+      name='source', full_name='chromiumos.test.api.CacheRequest.source',
+      index=1, containing_type=None, fields=[]),
+  ],
+  serialized_start=1118,
+  serialized_end=1644,
+)
+
+
+_CACHERESPONSE_SUCCESS = _descriptor.Descriptor(
+  name='Success',
+  full_name='chromiumos.test.api.CacheResponse.Success',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1790,
+  serialized_end=1799,
+)
+
+_CACHERESPONSE_FAILURE = _descriptor.Descriptor(
+  name='Failure',
+  full_name='chromiumos.test.api.CacheResponse.Failure',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='error_message', full_name='chromiumos.test.api.CacheResponse.Failure.error_message', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1801,
+  serialized_end=1833,
+)
+
+_CACHERESPONSE = _descriptor.Descriptor(
+  name='CacheResponse',
+  full_name='chromiumos.test.api.CacheResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='success', full_name='chromiumos.test.api.CacheResponse.success', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='failure', full_name='chromiumos.test.api.CacheResponse.failure', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[_CACHERESPONSE_SUCCESS, _CACHERESPONSE_FAILURE, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+    _descriptor.OneofDescriptor(
+      name='result', full_name='chromiumos.test.api.CacheResponse.result',
+      index=0, containing_type=None, fields=[]),
+  ],
+  serialized_start=1647,
+  serialized_end=1843,
+)
+
+
+_CACHEMETADATA = _descriptor.Descriptor(
+  name='CacheMetadata',
+  full_name='chromiumos.test.api.CacheMetadata',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1845,
+  serialized_end=1860,
+)
+
+
+_FORCERECONNECTREQUEST = _descriptor.Descriptor(
+  name='ForceReconnectRequest',
+  full_name='chromiumos.test.api.ForceReconnectRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1862,
+  serialized_end=1885,
+)
+
+
+_FORCERECONNECTRESPONSE_SUCCESS = _descriptor.Descriptor(
+  name='Success',
+  full_name='chromiumos.test.api.ForceReconnectResponse.Success',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1790,
+  serialized_end=1799,
+)
+
+_FORCERECONNECTRESPONSE_FAILURE = _descriptor.Descriptor(
+  name='Failure',
+  full_name='chromiumos.test.api.ForceReconnectResponse.Failure',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='error_message', full_name='chromiumos.test.api.ForceReconnectResponse.Failure.error_message', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1801,
+  serialized_end=1833,
+)
+
+_FORCERECONNECTRESPONSE = _descriptor.Descriptor(
+  name='ForceReconnectResponse',
+  full_name='chromiumos.test.api.ForceReconnectResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='success', full_name='chromiumos.test.api.ForceReconnectResponse.success', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='failure', full_name='chromiumos.test.api.ForceReconnectResponse.failure', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[_FORCERECONNECTRESPONSE_SUCCESS, _FORCERECONNECTRESPONSE_FAILURE, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+    _descriptor.OneofDescriptor(
+      name='result', full_name='chromiumos.test.api.ForceReconnectResponse.result',
+      index=0, containing_type=None, fields=[]),
+  ],
+  serialized_start=1888,
+  serialized_end=2111,
+)
+
+
+_FORCERECONNECTMETADATA = _descriptor.Descriptor(
+  name='ForceReconnectMetadata',
+  full_name='chromiumos.test.api.ForceReconnectMetadata',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2113,
+  serialized_end=2137,
+)
+
+
 _DETECTDEVICECONFIGIDREQUEST = _descriptor.Descriptor(
   name='DetectDeviceConfigIdRequest',
   full_name='chromiumos.test.api.DetectDeviceConfigIdRequest',
@@ -562,8 +1044,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1117,
-  serialized_end=1146,
+  serialized_start=2139,
+  serialized_end=2168,
 )
 
 
@@ -593,8 +1075,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1337,
-  serialized_end=1426,
+  serialized_start=2359,
+  serialized_end=2448,
 )
 
 _DETECTDEVICECONFIGIDRESPONSE_FAILURE = _descriptor.Descriptor(
@@ -623,8 +1105,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1428,
-  serialized_end=1460,
+  serialized_start=1801,
+  serialized_end=1833,
 )
 
 _DETECTDEVICECONFIGIDRESPONSE = _descriptor.Descriptor(
@@ -663,8 +1145,8 @@
       name='result', full_name='chromiumos.test.api.DetectDeviceConfigIdResponse.result',
       index=0, containing_type=None, fields=[]),
   ],
-  serialized_start=1149,
-  serialized_end=1470,
+  serialized_start=2171,
+  serialized_end=2492,
 )
 
 _EXECCOMMANDREQUEST.fields_by_name['stdout'].enum_type = _OUTPUT
@@ -683,6 +1165,51 @@
   _FETCHCRASHESRESPONSE.fields_by_name['core'])
 _FETCHCRASHESRESPONSE.fields_by_name['core'].containing_oneof = _FETCHCRASHESRESPONSE.oneofs_by_name['data']
 _CRASHINFO.fields_by_name['fields'].message_type = _CRASHMETADATA
+_CACHEREQUEST_LOCALFILE.containing_type = _CACHEREQUEST
+_CACHEREQUEST_PIPE.containing_type = _CACHEREQUEST
+_CACHEREQUEST_GSFILE.containing_type = _CACHEREQUEST
+_CACHEREQUEST_GSZIPFILE.containing_type = _CACHEREQUEST
+_CACHEREQUEST_GSTARFILE.containing_type = _CACHEREQUEST
+_CACHEREQUEST.fields_by_name['file'].message_type = _CACHEREQUEST_LOCALFILE
+_CACHEREQUEST.fields_by_name['pipe'].message_type = _CACHEREQUEST_PIPE
+_CACHEREQUEST.fields_by_name['gs_file'].message_type = _CACHEREQUEST_GSFILE
+_CACHEREQUEST.fields_by_name['gs_zip_file'].message_type = _CACHEREQUEST_GSZIPFILE
+_CACHEREQUEST.fields_by_name['gs_tar_file'].message_type = _CACHEREQUEST_GSTARFILE
+_CACHEREQUEST.oneofs_by_name['destination'].fields.append(
+  _CACHEREQUEST.fields_by_name['file'])
+_CACHEREQUEST.fields_by_name['file'].containing_oneof = _CACHEREQUEST.oneofs_by_name['destination']
+_CACHEREQUEST.oneofs_by_name['destination'].fields.append(
+  _CACHEREQUEST.fields_by_name['pipe'])
+_CACHEREQUEST.fields_by_name['pipe'].containing_oneof = _CACHEREQUEST.oneofs_by_name['destination']
+_CACHEREQUEST.oneofs_by_name['source'].fields.append(
+  _CACHEREQUEST.fields_by_name['gs_file'])
+_CACHEREQUEST.fields_by_name['gs_file'].containing_oneof = _CACHEREQUEST.oneofs_by_name['source']
+_CACHEREQUEST.oneofs_by_name['source'].fields.append(
+  _CACHEREQUEST.fields_by_name['gs_zip_file'])
+_CACHEREQUEST.fields_by_name['gs_zip_file'].containing_oneof = _CACHEREQUEST.oneofs_by_name['source']
+_CACHEREQUEST.oneofs_by_name['source'].fields.append(
+  _CACHEREQUEST.fields_by_name['gs_tar_file'])
+_CACHEREQUEST.fields_by_name['gs_tar_file'].containing_oneof = _CACHEREQUEST.oneofs_by_name['source']
+_CACHERESPONSE_SUCCESS.containing_type = _CACHERESPONSE
+_CACHERESPONSE_FAILURE.containing_type = _CACHERESPONSE
+_CACHERESPONSE.fields_by_name['success'].message_type = _CACHERESPONSE_SUCCESS
+_CACHERESPONSE.fields_by_name['failure'].message_type = _CACHERESPONSE_FAILURE
+_CACHERESPONSE.oneofs_by_name['result'].fields.append(
+  _CACHERESPONSE.fields_by_name['success'])
+_CACHERESPONSE.fields_by_name['success'].containing_oneof = _CACHERESPONSE.oneofs_by_name['result']
+_CACHERESPONSE.oneofs_by_name['result'].fields.append(
+  _CACHERESPONSE.fields_by_name['failure'])
+_CACHERESPONSE.fields_by_name['failure'].containing_oneof = _CACHERESPONSE.oneofs_by_name['result']
+_FORCERECONNECTRESPONSE_SUCCESS.containing_type = _FORCERECONNECTRESPONSE
+_FORCERECONNECTRESPONSE_FAILURE.containing_type = _FORCERECONNECTRESPONSE
+_FORCERECONNECTRESPONSE.fields_by_name['success'].message_type = _FORCERECONNECTRESPONSE_SUCCESS
+_FORCERECONNECTRESPONSE.fields_by_name['failure'].message_type = _FORCERECONNECTRESPONSE_FAILURE
+_FORCERECONNECTRESPONSE.oneofs_by_name['result'].fields.append(
+  _FORCERECONNECTRESPONSE.fields_by_name['success'])
+_FORCERECONNECTRESPONSE.fields_by_name['success'].containing_oneof = _FORCERECONNECTRESPONSE.oneofs_by_name['result']
+_FORCERECONNECTRESPONSE.oneofs_by_name['result'].fields.append(
+  _FORCERECONNECTRESPONSE.fields_by_name['failure'])
+_FORCERECONNECTRESPONSE.fields_by_name['failure'].containing_oneof = _FORCERECONNECTRESPONSE.oneofs_by_name['result']
 _DETECTDEVICECONFIGIDRESPONSE_SUCCESS.fields_by_name['detected_scan_config'].message_type = chromiumos_dot_config_dot_api_dot_device__config__id__pb2._DEVICECONFIGID_SCANCONFIG
 _DETECTDEVICECONFIGIDRESPONSE_SUCCESS.containing_type = _DETECTDEVICECONFIGIDRESPONSE
 _DETECTDEVICECONFIGIDRESPONSE_FAILURE.containing_type = _DETECTDEVICECONFIGIDRESPONSE
@@ -704,6 +1231,12 @@
 DESCRIPTOR.message_types_by_name['RestartRequest'] = _RESTARTREQUEST
 DESCRIPTOR.message_types_by_name['RestartResponse'] = _RESTARTRESPONSE
 DESCRIPTOR.message_types_by_name['RestartMetadata'] = _RESTARTMETADATA
+DESCRIPTOR.message_types_by_name['CacheRequest'] = _CACHEREQUEST
+DESCRIPTOR.message_types_by_name['CacheResponse'] = _CACHERESPONSE
+DESCRIPTOR.message_types_by_name['CacheMetadata'] = _CACHEMETADATA
+DESCRIPTOR.message_types_by_name['ForceReconnectRequest'] = _FORCERECONNECTREQUEST
+DESCRIPTOR.message_types_by_name['ForceReconnectResponse'] = _FORCERECONNECTRESPONSE
+DESCRIPTOR.message_types_by_name['ForceReconnectMetadata'] = _FORCERECONNECTMETADATA
 DESCRIPTOR.message_types_by_name['DetectDeviceConfigIdRequest'] = _DETECTDEVICECONFIGIDREQUEST
 DESCRIPTOR.message_types_by_name['DetectDeviceConfigIdResponse'] = _DETECTDEVICECONFIGIDRESPONSE
 DESCRIPTOR.enum_types_by_name['Output'] = _OUTPUT
@@ -787,6 +1320,120 @@
   })
 _sym_db.RegisterMessage(RestartMetadata)
 
+CacheRequest = _reflection.GeneratedProtocolMessageType('CacheRequest', (_message.Message,), {
+
+  'LocalFile' : _reflection.GeneratedProtocolMessageType('LocalFile', (_message.Message,), {
+    'DESCRIPTOR' : _CACHEREQUEST_LOCALFILE,
+    '__module__' : 'chromiumos.test.api.dut_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.CacheRequest.LocalFile)
+    })
+  ,
+
+  'Pipe' : _reflection.GeneratedProtocolMessageType('Pipe', (_message.Message,), {
+    'DESCRIPTOR' : _CACHEREQUEST_PIPE,
+    '__module__' : 'chromiumos.test.api.dut_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.CacheRequest.Pipe)
+    })
+  ,
+
+  'GSFile' : _reflection.GeneratedProtocolMessageType('GSFile', (_message.Message,), {
+    'DESCRIPTOR' : _CACHEREQUEST_GSFILE,
+    '__module__' : 'chromiumos.test.api.dut_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.CacheRequest.GSFile)
+    })
+  ,
+
+  'GSZipFile' : _reflection.GeneratedProtocolMessageType('GSZipFile', (_message.Message,), {
+    'DESCRIPTOR' : _CACHEREQUEST_GSZIPFILE,
+    '__module__' : 'chromiumos.test.api.dut_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.CacheRequest.GSZipFile)
+    })
+  ,
+
+  'GSTARFile' : _reflection.GeneratedProtocolMessageType('GSTARFile', (_message.Message,), {
+    'DESCRIPTOR' : _CACHEREQUEST_GSTARFILE,
+    '__module__' : 'chromiumos.test.api.dut_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.CacheRequest.GSTARFile)
+    })
+  ,
+  'DESCRIPTOR' : _CACHEREQUEST,
+  '__module__' : 'chromiumos.test.api.dut_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.CacheRequest)
+  })
+_sym_db.RegisterMessage(CacheRequest)
+_sym_db.RegisterMessage(CacheRequest.LocalFile)
+_sym_db.RegisterMessage(CacheRequest.Pipe)
+_sym_db.RegisterMessage(CacheRequest.GSFile)
+_sym_db.RegisterMessage(CacheRequest.GSZipFile)
+_sym_db.RegisterMessage(CacheRequest.GSTARFile)
+
+CacheResponse = _reflection.GeneratedProtocolMessageType('CacheResponse', (_message.Message,), {
+
+  'Success' : _reflection.GeneratedProtocolMessageType('Success', (_message.Message,), {
+    'DESCRIPTOR' : _CACHERESPONSE_SUCCESS,
+    '__module__' : 'chromiumos.test.api.dut_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.CacheResponse.Success)
+    })
+  ,
+
+  'Failure' : _reflection.GeneratedProtocolMessageType('Failure', (_message.Message,), {
+    'DESCRIPTOR' : _CACHERESPONSE_FAILURE,
+    '__module__' : 'chromiumos.test.api.dut_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.CacheResponse.Failure)
+    })
+  ,
+  'DESCRIPTOR' : _CACHERESPONSE,
+  '__module__' : 'chromiumos.test.api.dut_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.CacheResponse)
+  })
+_sym_db.RegisterMessage(CacheResponse)
+_sym_db.RegisterMessage(CacheResponse.Success)
+_sym_db.RegisterMessage(CacheResponse.Failure)
+
+CacheMetadata = _reflection.GeneratedProtocolMessageType('CacheMetadata', (_message.Message,), {
+  'DESCRIPTOR' : _CACHEMETADATA,
+  '__module__' : 'chromiumos.test.api.dut_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.CacheMetadata)
+  })
+_sym_db.RegisterMessage(CacheMetadata)
+
+ForceReconnectRequest = _reflection.GeneratedProtocolMessageType('ForceReconnectRequest', (_message.Message,), {
+  'DESCRIPTOR' : _FORCERECONNECTREQUEST,
+  '__module__' : 'chromiumos.test.api.dut_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.ForceReconnectRequest)
+  })
+_sym_db.RegisterMessage(ForceReconnectRequest)
+
+ForceReconnectResponse = _reflection.GeneratedProtocolMessageType('ForceReconnectResponse', (_message.Message,), {
+
+  'Success' : _reflection.GeneratedProtocolMessageType('Success', (_message.Message,), {
+    'DESCRIPTOR' : _FORCERECONNECTRESPONSE_SUCCESS,
+    '__module__' : 'chromiumos.test.api.dut_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.ForceReconnectResponse.Success)
+    })
+  ,
+
+  'Failure' : _reflection.GeneratedProtocolMessageType('Failure', (_message.Message,), {
+    'DESCRIPTOR' : _FORCERECONNECTRESPONSE_FAILURE,
+    '__module__' : 'chromiumos.test.api.dut_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.ForceReconnectResponse.Failure)
+    })
+  ,
+  'DESCRIPTOR' : _FORCERECONNECTRESPONSE,
+  '__module__' : 'chromiumos.test.api.dut_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.ForceReconnectResponse)
+  })
+_sym_db.RegisterMessage(ForceReconnectResponse)
+_sym_db.RegisterMessage(ForceReconnectResponse.Success)
+_sym_db.RegisterMessage(ForceReconnectResponse.Failure)
+
+ForceReconnectMetadata = _reflection.GeneratedProtocolMessageType('ForceReconnectMetadata', (_message.Message,), {
+  'DESCRIPTOR' : _FORCERECONNECTMETADATA,
+  '__module__' : 'chromiumos.test.api.dut_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.ForceReconnectMetadata)
+  })
+_sym_db.RegisterMessage(ForceReconnectMetadata)
+
 DetectDeviceConfigIdRequest = _reflection.GeneratedProtocolMessageType('DetectDeviceConfigIdRequest', (_message.Message,), {
   'DESCRIPTOR' : _DETECTDEVICECONFIGIDREQUEST,
   '__module__' : 'chromiumos.test.api.dut_service_pb2'
@@ -826,8 +1473,8 @@
   file=DESCRIPTOR,
   index=0,
   serialized_options=None,
-  serialized_start=1519,
-  serialized_end=1983,
+  serialized_start=2541,
+  serialized_end=3270,
   methods=[
   _descriptor.MethodDescriptor(
     name='ExecCommand',
@@ -865,6 +1512,24 @@
     output_type=_DETECTDEVICECONFIGIDRESPONSE,
     serialized_options=None,
   ),
+  _descriptor.MethodDescriptor(
+    name='Cache',
+    full_name='chromiumos.test.api.DutService.Cache',
+    index=4,
+    containing_service=None,
+    input_type=_CACHEREQUEST,
+    output_type=chromiumos_dot_longrunning_dot_operations__pb2._OPERATION,
+    serialized_options=b'\322A\036\n\rCacheResponse\022\rCacheMetadata',
+  ),
+  _descriptor.MethodDescriptor(
+    name='ForceReconnect',
+    full_name='chromiumos.test.api.DutService.ForceReconnect',
+    index=5,
+    containing_service=None,
+    input_type=_FORCERECONNECTREQUEST,
+    output_type=chromiumos_dot_longrunning_dot_operations__pb2._OPERATION,
+    serialized_options=b'\322A0\n\026ForceReconnectResponse\022\026ForceReconnectMetadata',
+  ),
 ])
 _sym_db.RegisterServiceDescriptor(_DUTSERVICE)
 
diff --git a/api/gen_sdk/chromiumos/test/api/plan_pb2.py b/api/gen_sdk/chromiumos/test/api/plan_pb2.py
index dc028a6..791b2b9 100644
--- a/api/gen_sdk/chromiumos/test/api/plan_pb2.py
+++ b/api/gen_sdk/chromiumos/test/api/plan_pb2.py
@@ -19,7 +19,7 @@
   package='chromiumos.test.api',
   syntax='proto3',
   serialized_options=b'Z-go.chromium.org/chromiumos/config/go/test/api',
-  serialized_pb=b'\n\x1e\x63hromiumos/test/api/plan.proto\x12\x13\x63hromiumos.test.api\x1a\'chromiumos/test/api/coverage_rule.proto\"\x9c\x01\n\nHWTestPlan\x12\x36\n\x02id\x18\x01 \x01(\x0b\x32*.chromiumos.test.api.HWTestPlan.TestPlanId\x12\x39\n\x0e\x63overage_rules\x18\x02 \x03(\x0b\x32!.chromiumos.test.api.CoverageRule\x1a\x1b\n\nTestPlanId\x12\r\n\x05value\x18\x01 \x01(\tB/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
+  serialized_pb=b'\n\x1e\x63hromiumos/test/api/plan.proto\x12\x13\x63hromiumos.test.api\x1a\'chromiumos/test/api/coverage_rule.proto\"\xa0\x01\n\nHWTestPlan\x12\x36\n\x02id\x18\x01 \x01(\x0b\x32*.chromiumos.test.api.HWTestPlan.TestPlanId\x12\x39\n\x0e\x63overage_rules\x18\x02 \x03(\x0b\x32!.chromiumos.test.api.CoverageRule\x1a\x1b\n\nTestPlanId\x12\r\n\x05value\x18\x01 \x01(\t:\x02\x18\x01\x42/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
   ,
   dependencies=[chromiumos_dot_test_dot_api_dot_coverage__rule__pb2.DESCRIPTOR,])
 
@@ -83,14 +83,14 @@
   nested_types=[_HWTESTPLAN_TESTPLANID, ],
   enum_types=[
   ],
-  serialized_options=None,
+  serialized_options=b'\030\001',
   is_extendable=False,
   syntax='proto3',
   extension_ranges=[],
   oneofs=[
   ],
   serialized_start=97,
-  serialized_end=253,
+  serialized_end=257,
 )
 
 _HWTESTPLAN_TESTPLANID.containing_type = _HWTESTPLAN
@@ -116,4 +116,5 @@
 
 
 DESCRIPTOR._options = None
+_HWTESTPLAN._options = None
 # @@protoc_insertion_point(module_scope)
diff --git a/api/gen_sdk/chromiumos/test/api/provision_service_pb2.py b/api/gen_sdk/chromiumos/test/api/provision_service_pb2.py
index b3a42d5..40fd286 100644
--- a/api/gen_sdk/chromiumos/test/api/provision_service_pb2.py
+++ b/api/gen_sdk/chromiumos/test/api/provision_service_pb2.py
@@ -21,7 +21,7 @@
   package='chromiumos.test.api',
   syntax='proto3',
   serialized_options=b'Z-go.chromium.org/chromiumos/config/go/test/api',
-  serialized_pb=b'\n+chromiumos/test/api/provision_service.proto\x12\x13\x63hromiumos.test.api\x1a*chromiumos/build/api/firmware_config.proto\x1a\'chromiumos/longrunning/operations.proto\x1a\x1d\x63hromiumos/storage_path.proto\"\x10\n\x0eInstallSuccess\"\xaf\x02\n\x0eInstallFailure\x12:\n\x06reason\x18\x01 \x01(\x0e\x32*.chromiumos.test.api.InstallFailure.Reason\"\xe0\x01\n\x06Reason\x12\x1a\n\x16REASON_INVALID_REQUEST\x10\x00\x12(\n$REASON_DUT_UNREACHABLE_PRE_PROVISION\x10\x01\x12#\n\x1fREASON_DOWNLOADING_IMAGE_FAILED\x10\x02\x12 \n\x1cREASON_PROVISIONING_TIMEDOUT\x10\x03\x12\x1e\n\x1aREASON_PROVISIONING_FAILED\x10\x04\x12)\n%REASON_DUT_UNREACHABLE_POST_PROVISION\x10\x05\"\x88\x02\n\x12InstallCrosRequest\x12\x30\n\x0f\x63ros_image_path\x18\x01 \x01(\x0b\x32\x17.chromiumos.StoragePath\x12\x42\n\tdlc_specs\x18\x02 \x03(\x0b\x32/.chromiumos.test.api.InstallCrosRequest.DLCSpec\x12\x19\n\x11preserve_stateful\x18\x03 \x01(\x08\x12\x16\n\x0eprevent_reboot\x18\x04 \x01(\x08\x12\x32\n\x11overwrite_payload\x18\x05 \x01(\x0b\x32\x17.chromiumos.StoragePath\x1a\x15\n\x07\x44LCSpec\x12\n\n\x02id\x18\x01 \x01(\t\"\x90\x01\n\x13InstallCrosResponse\x12\x36\n\x07success\x18\x01 \x01(\x0b\x32#.chromiumos.test.api.InstallSuccessH\x00\x12\x36\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32#.chromiumos.test.api.InstallFailureH\x00\x42\t\n\x07outcome\"\x15\n\x13InstallCrosMetadata\"J\n\x14InstallLacrosRequest\x12\x32\n\x11lacros_image_path\x18\x01 \x01(\x0b\x32\x17.chromiumos.StoragePath\"\x92\x01\n\x15InstallLacrosResponse\x12\x36\n\x07success\x18\x01 \x01(\x0b\x32#.chromiumos.test.api.InstallSuccessH\x00\x12\x36\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32#.chromiumos.test.api.InstallFailureH\x00\x42\t\n\x07outcome\"\x17\n\x15InstallLacrosMetadata\"D\n\x11InstallAshRequest\x12/\n\x0e\x61sh_image_path\x18\x01 \x01(\x0b\x32\x17.chromiumos.StoragePath\"\x8f\x01\n\x12InstallAshResponse\x12\x36\n\x07success\x18\x01 \x01(\x0b\x32#.chromiumos.test.api.InstallSuccessH\x00\x12\x36\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32#.chromiumos.test.api.InstallFailureH\x00\x42\t\n\x07outcome\"\x14\n\x12InstallAshMetadata\"D\n\x11InstallArcRequest\x12/\n\x0e\x61sh_image_path\x18\x01 \x01(\x0b\x32\x17.chromiumos.StoragePath\"\x8f\x01\n\x12InstallArcResponse\x12\x36\n\x07success\x18\x01 \x01(\x0b\x32#.chromiumos.test.api.InstallSuccessH\x00\x12\x36\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32#.chromiumos.test.api.InstallFailureH\x00\x42\t\n\x07outcome\"\x14\n\x12InstallArcMetadata\"W\n\x16InstallFirmwareRequest\x12=\n\x0f\x66irmware_config\x18\x01 \x01(\x0b\x32$.chromiumos.build.api.FirmwareConfig\"\x94\x01\n\x17InstallFirmwareResponse\x12\x36\n\x07success\x18\x01 \x01(\x0b\x32#.chromiumos.test.api.InstallSuccessH\x00\x12\x36\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32#.chromiumos.test.api.InstallFailureH\x00\x42\t\n\x07outcome\"\x19\n\x17InstallFirmwareMetadata2\xd9\x05\n\x10ProvisionService\x12\x88\x01\n\x0bInstallCros\x12\'.chromiumos.test.api.InstallCrosRequest\x1a!.chromiumos.longrunning.Operation\"-\xd2\x41*\n\x13InstallCrosResponse\x12\x13InstallCrosMetadata\x12\x90\x01\n\rInstallLacros\x12).chromiumos.test.api.InstallLacrosRequest\x1a!.chromiumos.longrunning.Operation\"1\xd2\x41.\n\x15InstallLacrosResponse\x12\x15InstallLacrosMetadata\x12\x84\x01\n\nInstallAsh\x12&.chromiumos.test.api.InstallAshRequest\x1a!.chromiumos.longrunning.Operation\"+\xd2\x41(\n\x12InstallAshResponse\x12\x12InstallAshMetadata\x12\x84\x01\n\nInstallArc\x12&.chromiumos.test.api.InstallArcRequest\x1a!.chromiumos.longrunning.Operation\"+\xd2\x41(\n\x12InstallArcResponse\x12\x12InstallArcMetadata\x12\x98\x01\n\x0fInstallFirmware\x12+.chromiumos.test.api.InstallFirmwareRequest\x1a!.chromiumos.longrunning.Operation\"5\xd2\x41\x32\n\x17InstallFirmwareResponse\x12\x17InstallFirmwareMetadataB/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
+  serialized_pb=b'\n+chromiumos/test/api/provision_service.proto\x12\x13\x63hromiumos.test.api\x1a*chromiumos/build/api/firmware_config.proto\x1a\'chromiumos/longrunning/operations.proto\x1a\x1d\x63hromiumos/storage_path.proto\"\x10\n\x0eInstallSuccess\"\xaf\x02\n\x0eInstallFailure\x12:\n\x06reason\x18\x01 \x01(\x0e\x32*.chromiumos.test.api.InstallFailure.Reason\"\xe0\x01\n\x06Reason\x12\x1a\n\x16REASON_INVALID_REQUEST\x10\x00\x12(\n$REASON_DUT_UNREACHABLE_PRE_PROVISION\x10\x01\x12#\n\x1fREASON_DOWNLOADING_IMAGE_FAILED\x10\x02\x12 \n\x1cREASON_PROVISIONING_TIMEDOUT\x10\x03\x12\x1e\n\x1aREASON_PROVISIONING_FAILED\x10\x04\x12)\n%REASON_DUT_UNREACHABLE_POST_PROVISION\x10\x05\"\x88\x02\n\x12InstallCrosRequest\x12\x30\n\x0f\x63ros_image_path\x18\x01 \x01(\x0b\x32\x17.chromiumos.StoragePath\x12\x42\n\tdlc_specs\x18\x02 \x03(\x0b\x32/.chromiumos.test.api.InstallCrosRequest.DLCSpec\x12\x19\n\x11preserve_stateful\x18\x03 \x01(\x08\x12\x16\n\x0eprevent_reboot\x18\x04 \x01(\x08\x12\x32\n\x11overwrite_payload\x18\x05 \x01(\x0b\x32\x17.chromiumos.StoragePath\x1a\x15\n\x07\x44LCSpec\x12\n\n\x02id\x18\x01 \x01(\t\"\x90\x01\n\x13InstallCrosResponse\x12\x36\n\x07success\x18\x01 \x01(\x0b\x32#.chromiumos.test.api.InstallSuccessH\x00\x12\x36\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32#.chromiumos.test.api.InstallFailureH\x00\x42\t\n\x07outcome\"\x15\n\x13InstallCrosMetadata\"J\n\x14InstallLacrosRequest\x12\x32\n\x11lacros_image_path\x18\x01 \x01(\x0b\x32\x17.chromiumos.StoragePath\"\x92\x01\n\x15InstallLacrosResponse\x12\x36\n\x07success\x18\x01 \x01(\x0b\x32#.chromiumos.test.api.InstallSuccessH\x00\x12\x36\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32#.chromiumos.test.api.InstallFailureH\x00\x42\t\n\x07outcome\"\x17\n\x15InstallLacrosMetadata\"D\n\x11InstallAshRequest\x12/\n\x0e\x61sh_image_path\x18\x01 \x01(\x0b\x32\x17.chromiumos.StoragePath\"\x8f\x01\n\x12InstallAshResponse\x12\x36\n\x07success\x18\x01 \x01(\x0b\x32#.chromiumos.test.api.InstallSuccessH\x00\x12\x36\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32#.chromiumos.test.api.InstallFailureH\x00\x42\t\n\x07outcome\"\x14\n\x12InstallAshMetadata\"D\n\x11InstallArcRequest\x12/\n\x0e\x61sh_image_path\x18\x01 \x01(\x0b\x32\x17.chromiumos.StoragePath\"\x8f\x01\n\x12InstallArcResponse\x12\x36\n\x07success\x18\x01 \x01(\x0b\x32#.chromiumos.test.api.InstallSuccessH\x00\x12\x36\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32#.chromiumos.test.api.InstallFailureH\x00\x42\t\n\x07outcome\"\x14\n\x12InstallArcMetadata\"y\n\x16InstallFirmwareRequest\x12=\n\x0f\x66irmware_config\x18\x01 \x01(\x0b\x32$.chromiumos.build.api.FirmwareConfig\x12\r\n\x05\x66orce\x18\x08 \x01(\x08\x12\x11\n\tuse_servo\x18\t \x01(\x08\"\x94\x01\n\x17InstallFirmwareResponse\x12\x36\n\x07success\x18\x01 \x01(\x0b\x32#.chromiumos.test.api.InstallSuccessH\x00\x12\x36\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32#.chromiumos.test.api.InstallFailureH\x00\x42\t\n\x07outcome\"\x19\n\x17InstallFirmwareMetadata2\xd9\x05\n\x10ProvisionService\x12\x88\x01\n\x0bInstallCros\x12\'.chromiumos.test.api.InstallCrosRequest\x1a!.chromiumos.longrunning.Operation\"-\xd2\x41*\n\x13InstallCrosResponse\x12\x13InstallCrosMetadata\x12\x90\x01\n\rInstallLacros\x12).chromiumos.test.api.InstallLacrosRequest\x1a!.chromiumos.longrunning.Operation\"1\xd2\x41.\n\x15InstallLacrosResponse\x12\x15InstallLacrosMetadata\x12\x84\x01\n\nInstallAsh\x12&.chromiumos.test.api.InstallAshRequest\x1a!.chromiumos.longrunning.Operation\"+\xd2\x41(\n\x12InstallAshResponse\x12\x12InstallAshMetadata\x12\x84\x01\n\nInstallArc\x12&.chromiumos.test.api.InstallArcRequest\x1a!.chromiumos.longrunning.Operation\"+\xd2\x41(\n\x12InstallArcResponse\x12\x12InstallArcMetadata\x12\x98\x01\n\x0fInstallFirmware\x12+.chromiumos.test.api.InstallFirmwareRequest\x1a!.chromiumos.longrunning.Operation\"5\xd2\x41\x32\n\x17InstallFirmwareResponse\x12\x17InstallFirmwareMetadataB/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
   ,
   dependencies=[chromiumos_dot_build_dot_api_dot_firmware__config__pb2.DESCRIPTOR,chromiumos_dot_longrunning_dot_operations__pb2.DESCRIPTOR,chromiumos_dot_storage__path__pb2.DESCRIPTOR,])
 
@@ -578,6 +578,20 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='force', full_name='chromiumos.test.api.InstallFirmwareRequest.force', index=1,
+      number=8, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='use_servo', full_name='chromiumos.test.api.InstallFirmwareRequest.use_servo', index=2,
+      number=9, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -591,7 +605,7 @@
   oneofs=[
   ],
   serialized_start=1671,
-  serialized_end=1758,
+  serialized_end=1792,
 )
 
 
@@ -631,8 +645,8 @@
       name='outcome', full_name='chromiumos.test.api.InstallFirmwareResponse.outcome',
       index=0, containing_type=None, fields=[]),
   ],
-  serialized_start=1761,
-  serialized_end=1909,
+  serialized_start=1795,
+  serialized_end=1943,
 )
 
 
@@ -655,8 +669,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1911,
-  serialized_end=1936,
+  serialized_start=1945,
+  serialized_end=1970,
 )
 
 _INSTALLFAILURE.fields_by_name['reason'].enum_type = _INSTALLFAILURE_REASON
@@ -864,8 +878,8 @@
   file=DESCRIPTOR,
   index=0,
   serialized_options=None,
-  serialized_start=1939,
-  serialized_end=2668,
+  serialized_start=1973,
+  serialized_end=2702,
   methods=[
   _descriptor.MethodDescriptor(
     name='InstallCros',
diff --git a/api/gen_sdk/chromiumos/test/api/provision_state_pb2.py b/api/gen_sdk/chromiumos/test/api/provision_state_pb2.py
index dd8101c..14aed7f 100644
--- a/api/gen_sdk/chromiumos/test/api/provision_state_pb2.py
+++ b/api/gen_sdk/chromiumos/test/api/provision_state_pb2.py
@@ -22,7 +22,7 @@
   package='chromiumos.test.api',
   syntax='proto3',
   serialized_options=b'Z-go.chromium.org/chromiumos/config/go/test/api',
-  serialized_pb=b'\n)chromiumos/test/api/provision_state.proto\x12\x13\x63hromiumos.test.api\x1a\x1e\x63hromiumos/build/api/dlc.proto\x1a*chromiumos/build/api/firmware_config.proto\x1a\"chromiumos/build/api/portage.proto\x1a\x1d\x63hromiumos/storage_path.proto\"\xa9\x04\n\x0eProvisionState\x12\x32\n\x02id\x18\x01 \x01(\x0b\x32&.chromiumos.test.api.ProvisionState.Id\x12\x36\n\x08\x66irmware\x18\x02 \x01(\x0b\x32$.chromiumos.build.api.FirmwareConfig\x12\x45\n\x0csystem_image\x18\x03 \x01(\x0b\x32/.chromiumos.test.api.ProvisionState.SystemImage\x12=\n\x08packages\x18\x04 \x03(\x0b\x32+.chromiumos.test.api.ProvisionState.Package\x12\x16\n\x0eprevent_reboot\x18\x05 \x01(\x08\x1a\x13\n\x02Id\x12\r\n\x05value\x18\x01 \x01(\t\x1a~\n\x0bSystemImage\x12\x0f\n\x07version\x18\x01 \x01(\t\x12\x32\n\x11system_image_path\x18\x02 \x01(\x0b\x32\x17.chromiumos.StoragePath\x12*\n\x04\x64lcs\x18\x03 \x03(\x0b\x32\x1c.chromiumos.build.api.Dlc.Id\x1ax\n\x07Package\x12>\n\x0fportage_package\x18\x01 \x01(\x0b\x32%.chromiumos.build.api.Portage.Package\x12-\n\x0cpackage_path\x18\x02 \x01(\x0b\x32\x17.chromiumos.StoragePath\"\xb4\x01\n\x0fProvisionConfig\x12\x36\n\x08\x66irmware\x18\x01 \x01(\x0b\x32$.chromiumos.build.api.FirmwareConfig\x12*\n\x04\x64lcs\x18\x02 \x03(\x0b\x32\x1c.chromiumos.build.api.Dlc.Id\x12=\n\x08packages\x18\x03 \x03(\x0b\x32+.chromiumos.test.api.ProvisionState.PackageB/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
+  serialized_pb=b'\n)chromiumos/test/api/provision_state.proto\x12\x13\x63hromiumos.test.api\x1a\x1e\x63hromiumos/build/api/dlc.proto\x1a*chromiumos/build/api/firmware_config.proto\x1a\"chromiumos/build/api/portage.proto\x1a\x1d\x63hromiumos/storage_path.proto\"\xde\x04\n\x0eProvisionState\x12\x32\n\x02id\x18\x01 \x01(\x0b\x32&.chromiumos.test.api.ProvisionState.Id\x12\x36\n\x08\x66irmware\x18\x02 \x01(\x0b\x32$.chromiumos.build.api.FirmwareConfig\x12\x45\n\x0csystem_image\x18\x03 \x01(\x0b\x32/.chromiumos.test.api.ProvisionState.SystemImage\x12=\n\x08packages\x18\x04 \x03(\x0b\x32+.chromiumos.test.api.ProvisionState.Package\x12\x16\n\x0eprevent_reboot\x18\x05 \x01(\x08\x1a\x13\n\x02Id\x12\r\n\x05value\x18\x01 \x01(\t\x1a\xb2\x01\n\x0bSystemImage\x12\x0f\n\x07version\x18\x01 \x01(\t\x12\x32\n\x11system_image_path\x18\x02 \x01(\x0b\x32\x17.chromiumos.StoragePath\x12*\n\x04\x64lcs\x18\x03 \x03(\x0b\x32\x1c.chromiumos.build.api.Dlc.Id\x12\x32\n\x11overwrite_payload\x18\x04 \x01(\x0b\x32\x17.chromiumos.StoragePath\x1ax\n\x07Package\x12>\n\x0fportage_package\x18\x01 \x01(\x0b\x32%.chromiumos.build.api.Portage.Package\x12-\n\x0cpackage_path\x18\x02 \x01(\x0b\x32\x17.chromiumos.StoragePath\"\xff\x01\n\x0fProvisionConfig\x12\x36\n\x08\x66irmware\x18\x01 \x01(\x0b\x32$.chromiumos.build.api.FirmwareConfig\x12*\n\x04\x64lcs\x18\x02 \x03(\x0b\x32\x1c.chromiumos.build.api.Dlc.Id\x12=\n\x08packages\x18\x03 \x03(\x0b\x32+.chromiumos.test.api.ProvisionState.Package\x12\x15\n\rboard_variant\x18\x04 \x01(\t\x12\x32\n\x11overwrite_payload\x18\x05 \x01(\x0b\x32\x17.chromiumos.StoragePathB/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
   ,
   dependencies=[chromiumos_dot_build_dot_api_dot_dlc__pb2.DESCRIPTOR,chromiumos_dot_build_dot_api_dot_firmware__config__pb2.DESCRIPTOR,chromiumos_dot_build_dot_api_dot_portage__pb2.DESCRIPTOR,chromiumos_dot_storage__path__pb2.DESCRIPTOR,])
 
@@ -87,6 +87,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='overwrite_payload', full_name='chromiumos.test.api.ProvisionState.SystemImage.overwrite_payload', index=3,
+      number=4, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -99,8 +106,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=515,
-  serialized_end=641,
+  serialized_start=516,
+  serialized_end=694,
 )
 
 _PROVISIONSTATE_PACKAGE = _descriptor.Descriptor(
@@ -136,8 +143,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=643,
-  serialized_end=763,
+  serialized_start=696,
+  serialized_end=816,
 )
 
 _PROVISIONSTATE = _descriptor.Descriptor(
@@ -195,7 +202,7 @@
   oneofs=[
   ],
   serialized_start=210,
-  serialized_end=763,
+  serialized_end=816,
 )
 
 
@@ -227,6 +234,20 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='board_variant', full_name='chromiumos.test.api.ProvisionConfig.board_variant', index=3,
+      number=4, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='overwrite_payload', full_name='chromiumos.test.api.ProvisionConfig.overwrite_payload', index=4,
+      number=5, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -239,13 +260,14 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=766,
-  serialized_end=946,
+  serialized_start=819,
+  serialized_end=1074,
 )
 
 _PROVISIONSTATE_ID.containing_type = _PROVISIONSTATE
 _PROVISIONSTATE_SYSTEMIMAGE.fields_by_name['system_image_path'].message_type = chromiumos_dot_storage__path__pb2._STORAGEPATH
 _PROVISIONSTATE_SYSTEMIMAGE.fields_by_name['dlcs'].message_type = chromiumos_dot_build_dot_api_dot_dlc__pb2._DLC_ID
+_PROVISIONSTATE_SYSTEMIMAGE.fields_by_name['overwrite_payload'].message_type = chromiumos_dot_storage__path__pb2._STORAGEPATH
 _PROVISIONSTATE_SYSTEMIMAGE.containing_type = _PROVISIONSTATE
 _PROVISIONSTATE_PACKAGE.fields_by_name['portage_package'].message_type = chromiumos_dot_build_dot_api_dot_portage__pb2._PORTAGE_PACKAGE
 _PROVISIONSTATE_PACKAGE.fields_by_name['package_path'].message_type = chromiumos_dot_storage__path__pb2._STORAGEPATH
@@ -257,6 +279,7 @@
 _PROVISIONCONFIG.fields_by_name['firmware'].message_type = chromiumos_dot_build_dot_api_dot_firmware__config__pb2._FIRMWARECONFIG
 _PROVISIONCONFIG.fields_by_name['dlcs'].message_type = chromiumos_dot_build_dot_api_dot_dlc__pb2._DLC_ID
 _PROVISIONCONFIG.fields_by_name['packages'].message_type = _PROVISIONSTATE_PACKAGE
+_PROVISIONCONFIG.fields_by_name['overwrite_payload'].message_type = chromiumos_dot_storage__path__pb2._STORAGEPATH
 DESCRIPTOR.message_types_by_name['ProvisionState'] = _PROVISIONSTATE
 DESCRIPTOR.message_types_by_name['ProvisionConfig'] = _PROVISIONCONFIG
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
diff --git a/api/gen_sdk/chromiumos/test/api/servod_service_pb2.py b/api/gen_sdk/chromiumos/test/api/servod_service_pb2.py
new file mode 100644
index 0000000..7815728
--- /dev/null
+++ b/api/gen_sdk/chromiumos/test/api/servod_service_pb2.py
@@ -0,0 +1,1041 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: chromiumos/test/api/servod_service.proto
+
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from chromite.api.gen_sdk.chromiumos.config.api.test.xmlrpc import xmlrpc_pb2 as chromiumos_dot_config_dot_api_dot_test_dot_xmlrpc_dot_xmlrpc__pb2
+from chromite.api.gen_sdk.chromiumos.longrunning import operations_pb2 as chromiumos_dot_longrunning_dot_operations__pb2
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='chromiumos/test/api/servod_service.proto',
+  package='chromiumos.test.api',
+  syntax='proto3',
+  serialized_options=b'Z-go.chromium.org/chromiumos/config/go/test/api',
+  serialized_pb=b'\n(chromiumos/test/api/servod_service.proto\x12\x13\x63hromiumos.test.api\x1a.chromiumos/config/api/test/xmlrpc/xmlrpc.proto\x1a\'chromiumos/longrunning/operations.proto\"\x8a\x02\n\x12StartServodRequest\x12\x17\n\x0fservo_host_path\x18\x01 \x01(\t\x12$\n\x1cservod_docker_container_name\x18\x02 \x01(\t\x12 \n\x18servod_docker_image_path\x18\x03 \x01(\t\x12\x13\n\x0bservod_port\x18\x04 \x01(\x05\x12\r\n\x05\x62oard\x18\x05 \x01(\t\x12\r\n\x05model\x18\x06 \x01(\t\x12\x13\n\x0bserial_name\x18\x07 \x01(\t\x12\r\n\x05\x64\x65\x62ug\x18\x08 \x01(\t\x12\x15\n\rrecovery_mode\x18\t \x01(\t\x12\x0e\n\x06\x63onfig\x18\n \x01(\t\x12\x15\n\rallow_dual_v4\x18\x0b \x01(\t\"\xd6\x01\n\x13StartServodResponse\x12\x43\n\x07success\x18\x01 \x01(\x0b\x32\x30.chromiumos.test.api.StartServodResponse.SuccessH\x00\x12\x43\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32\x30.chromiumos.test.api.StartServodResponse.FailureH\x00\x1a\t\n\x07Success\x1a \n\x07\x46\x61ilure\x12\x15\n\rerror_message\x18\x01 \x01(\tB\x08\n\x06result\"\x15\n\x13StartServodMetadata\"g\n\x11StopServodRequest\x12\x17\n\x0fservo_host_path\x18\x01 \x01(\t\x12$\n\x1cservod_docker_container_name\x18\x02 \x01(\t\x12\x13\n\x0bservod_port\x18\x03 \x01(\x05\"\xd3\x01\n\x12StopServodResponse\x12\x42\n\x07success\x18\x01 \x01(\x0b\x32/.chromiumos.test.api.StopServodResponse.SuccessH\x00\x12\x42\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32/.chromiumos.test.api.StopServodResponse.FailureH\x00\x1a\t\n\x07Success\x1a \n\x07\x46\x61ilure\x12\x15\n\rerror_message\x18\x01 \x01(\tB\x08\n\x06result\"\x14\n\x12StopServodMetadata\"o\n\x0e\x45xecCmdRequest\x12\x17\n\x0fservo_host_path\x18\x01 \x01(\t\x12$\n\x1cservod_docker_container_name\x18\x02 \x01(\t\x12\x0f\n\x07\x63ommand\x18\x03 \x01(\t\x12\r\n\x05stdin\x18\x04 \x01(\x0c\"\xc9\x01\n\x0f\x45xecCmdResponse\x12@\n\texit_info\x18\x01 \x01(\x0b\x32-.chromiumos.test.api.ExecCmdResponse.ExitInfo\x12\x0e\n\x06stdout\x18\x02 \x01(\x0c\x12\x0e\n\x06stderr\x18\x03 \x01(\x0c\x1aT\n\x08\x45xitInfo\x12\x0e\n\x06status\x18\x01 \x01(\x05\x12\x10\n\x08signaled\x18\x02 \x01(\x08\x12\x0f\n\x07started\x18\x03 \x01(\x08\x12\x15\n\rerror_message\x18\x04 \x01(\t\"\x11\n\x0f\x45xecCmdMetadata\"\x8f\x02\n\x11\x43\x61llServodRequest\x12\x17\n\x0fservo_host_path\x18\x01 \x01(\t\x12$\n\x1cservod_docker_container_name\x18\x02 \x01(\t\x12\x13\n\x0bservod_port\x18\x03 \x01(\x05\x12=\n\x06method\x18\x04 \x01(\x0e\x32-.chromiumos.test.api.CallServodRequest.Method\x12\x36\n\x04\x61rgs\x18\x05 \x03(\x0b\x32(.chromiumos.config.api.test.xmlrpc.Value\"/\n\x06Method\x12\x07\n\x03\x44OC\x10\x00\x12\x07\n\x03GET\x10\x01\x12\x07\n\x03SET\x10\x02\x12\n\n\x06HWINIT\x10\x03\"\x8d\x02\n\x12\x43\x61llServodResponse\x12\x42\n\x07success\x18\x01 \x01(\x0b\x32/.chromiumos.test.api.CallServodResponse.SuccessH\x00\x12\x42\n\x07\x66\x61ilure\x18\x02 \x01(\x0b\x32/.chromiumos.test.api.CallServodResponse.FailureH\x00\x1a\x43\n\x07Success\x12\x38\n\x06result\x18\x01 \x01(\x0b\x32(.chromiumos.config.api.test.xmlrpc.Value\x1a \n\x07\x46\x61ilure\x12\x15\n\rerror_message\x18\x01 \x01(\tB\x08\n\x06result\"\x14\n\x12\x43\x61llServodMetadata2\xd6\x03\n\rServodService\x12\x88\x01\n\x0bStartServod\x12\'.chromiumos.test.api.StartServodRequest\x1a!.chromiumos.longrunning.Operation\"-\xd2\x41*\n\x13StartServodResponse\x12\x13StartServodMetadata\x12\x84\x01\n\nStopServod\x12&.chromiumos.test.api.StopServodRequest\x1a!.chromiumos.longrunning.Operation\"+\xd2\x41(\n\x12StopServodResponse\x12\x12StopServodMetadata\x12T\n\x07\x45xecCmd\x12#.chromiumos.test.api.ExecCmdRequest\x1a$.chromiumos.test.api.ExecCmdResponse\x12]\n\nCallServod\x12&.chromiumos.test.api.CallServodRequest\x1a\'.chromiumos.test.api.CallServodResponseB/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
+  ,
+  dependencies=[chromiumos_dot_config_dot_api_dot_test_dot_xmlrpc_dot_xmlrpc__pb2.DESCRIPTOR,chromiumos_dot_longrunning_dot_operations__pb2.DESCRIPTOR,])
+
+
+
+_CALLSERVODREQUEST_METHOD = _descriptor.EnumDescriptor(
+  name='Method',
+  full_name='chromiumos.test.api.CallServodRequest.Method',
+  filename=None,
+  file=DESCRIPTOR,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='DOC', index=0, number=0,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='GET', index=1, number=1,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='SET', index=2, number=2,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='HWINIT', index=3, number=3,
+      serialized_options=None,
+      type=None),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=1565,
+  serialized_end=1612,
+)
+_sym_db.RegisterEnumDescriptor(_CALLSERVODREQUEST_METHOD)
+
+
+_STARTSERVODREQUEST = _descriptor.Descriptor(
+  name='StartServodRequest',
+  full_name='chromiumos.test.api.StartServodRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='servo_host_path', full_name='chromiumos.test.api.StartServodRequest.servo_host_path', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='servod_docker_container_name', full_name='chromiumos.test.api.StartServodRequest.servod_docker_container_name', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='servod_docker_image_path', full_name='chromiumos.test.api.StartServodRequest.servod_docker_image_path', index=2,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='servod_port', full_name='chromiumos.test.api.StartServodRequest.servod_port', index=3,
+      number=4, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='board', full_name='chromiumos.test.api.StartServodRequest.board', index=4,
+      number=5, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='model', full_name='chromiumos.test.api.StartServodRequest.model', index=5,
+      number=6, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='serial_name', full_name='chromiumos.test.api.StartServodRequest.serial_name', index=6,
+      number=7, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='debug', full_name='chromiumos.test.api.StartServodRequest.debug', index=7,
+      number=8, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='recovery_mode', full_name='chromiumos.test.api.StartServodRequest.recovery_mode', index=8,
+      number=9, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='config', full_name='chromiumos.test.api.StartServodRequest.config', index=9,
+      number=10, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='allow_dual_v4', full_name='chromiumos.test.api.StartServodRequest.allow_dual_v4', index=10,
+      number=11, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=155,
+  serialized_end=421,
+)
+
+
+_STARTSERVODRESPONSE_SUCCESS = _descriptor.Descriptor(
+  name='Success',
+  full_name='chromiumos.test.api.StartServodResponse.Success',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=585,
+  serialized_end=594,
+)
+
+_STARTSERVODRESPONSE_FAILURE = _descriptor.Descriptor(
+  name='Failure',
+  full_name='chromiumos.test.api.StartServodResponse.Failure',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='error_message', full_name='chromiumos.test.api.StartServodResponse.Failure.error_message', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=596,
+  serialized_end=628,
+)
+
+_STARTSERVODRESPONSE = _descriptor.Descriptor(
+  name='StartServodResponse',
+  full_name='chromiumos.test.api.StartServodResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='success', full_name='chromiumos.test.api.StartServodResponse.success', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='failure', full_name='chromiumos.test.api.StartServodResponse.failure', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[_STARTSERVODRESPONSE_SUCCESS, _STARTSERVODRESPONSE_FAILURE, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+    _descriptor.OneofDescriptor(
+      name='result', full_name='chromiumos.test.api.StartServodResponse.result',
+      index=0, containing_type=None, fields=[]),
+  ],
+  serialized_start=424,
+  serialized_end=638,
+)
+
+
+_STARTSERVODMETADATA = _descriptor.Descriptor(
+  name='StartServodMetadata',
+  full_name='chromiumos.test.api.StartServodMetadata',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=640,
+  serialized_end=661,
+)
+
+
+_STOPSERVODREQUEST = _descriptor.Descriptor(
+  name='StopServodRequest',
+  full_name='chromiumos.test.api.StopServodRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='servo_host_path', full_name='chromiumos.test.api.StopServodRequest.servo_host_path', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='servod_docker_container_name', full_name='chromiumos.test.api.StopServodRequest.servod_docker_container_name', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='servod_port', full_name='chromiumos.test.api.StopServodRequest.servod_port', index=2,
+      number=3, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=663,
+  serialized_end=766,
+)
+
+
+_STOPSERVODRESPONSE_SUCCESS = _descriptor.Descriptor(
+  name='Success',
+  full_name='chromiumos.test.api.StopServodResponse.Success',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=585,
+  serialized_end=594,
+)
+
+_STOPSERVODRESPONSE_FAILURE = _descriptor.Descriptor(
+  name='Failure',
+  full_name='chromiumos.test.api.StopServodResponse.Failure',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='error_message', full_name='chromiumos.test.api.StopServodResponse.Failure.error_message', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=596,
+  serialized_end=628,
+)
+
+_STOPSERVODRESPONSE = _descriptor.Descriptor(
+  name='StopServodResponse',
+  full_name='chromiumos.test.api.StopServodResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='success', full_name='chromiumos.test.api.StopServodResponse.success', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='failure', full_name='chromiumos.test.api.StopServodResponse.failure', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[_STOPSERVODRESPONSE_SUCCESS, _STOPSERVODRESPONSE_FAILURE, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+    _descriptor.OneofDescriptor(
+      name='result', full_name='chromiumos.test.api.StopServodResponse.result',
+      index=0, containing_type=None, fields=[]),
+  ],
+  serialized_start=769,
+  serialized_end=980,
+)
+
+
+_STOPSERVODMETADATA = _descriptor.Descriptor(
+  name='StopServodMetadata',
+  full_name='chromiumos.test.api.StopServodMetadata',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=982,
+  serialized_end=1002,
+)
+
+
+_EXECCMDREQUEST = _descriptor.Descriptor(
+  name='ExecCmdRequest',
+  full_name='chromiumos.test.api.ExecCmdRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='servo_host_path', full_name='chromiumos.test.api.ExecCmdRequest.servo_host_path', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='servod_docker_container_name', full_name='chromiumos.test.api.ExecCmdRequest.servod_docker_container_name', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='command', full_name='chromiumos.test.api.ExecCmdRequest.command', index=2,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='stdin', full_name='chromiumos.test.api.ExecCmdRequest.stdin', index=3,
+      number=4, type=12, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"",
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1004,
+  serialized_end=1115,
+)
+
+
+_EXECCMDRESPONSE_EXITINFO = _descriptor.Descriptor(
+  name='ExitInfo',
+  full_name='chromiumos.test.api.ExecCmdResponse.ExitInfo',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='status', full_name='chromiumos.test.api.ExecCmdResponse.ExitInfo.status', index=0,
+      number=1, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='signaled', full_name='chromiumos.test.api.ExecCmdResponse.ExitInfo.signaled', index=1,
+      number=2, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='started', full_name='chromiumos.test.api.ExecCmdResponse.ExitInfo.started', index=2,
+      number=3, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='error_message', full_name='chromiumos.test.api.ExecCmdResponse.ExitInfo.error_message', index=3,
+      number=4, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1235,
+  serialized_end=1319,
+)
+
+_EXECCMDRESPONSE = _descriptor.Descriptor(
+  name='ExecCmdResponse',
+  full_name='chromiumos.test.api.ExecCmdResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='exit_info', full_name='chromiumos.test.api.ExecCmdResponse.exit_info', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='stdout', full_name='chromiumos.test.api.ExecCmdResponse.stdout', index=1,
+      number=2, type=12, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"",
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='stderr', full_name='chromiumos.test.api.ExecCmdResponse.stderr', index=2,
+      number=3, type=12, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"",
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[_EXECCMDRESPONSE_EXITINFO, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1118,
+  serialized_end=1319,
+)
+
+
+_EXECCMDMETADATA = _descriptor.Descriptor(
+  name='ExecCmdMetadata',
+  full_name='chromiumos.test.api.ExecCmdMetadata',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1321,
+  serialized_end=1338,
+)
+
+
+_CALLSERVODREQUEST = _descriptor.Descriptor(
+  name='CallServodRequest',
+  full_name='chromiumos.test.api.CallServodRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='servo_host_path', full_name='chromiumos.test.api.CallServodRequest.servo_host_path', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='servod_docker_container_name', full_name='chromiumos.test.api.CallServodRequest.servod_docker_container_name', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='servod_port', full_name='chromiumos.test.api.CallServodRequest.servod_port', index=2,
+      number=3, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='method', full_name='chromiumos.test.api.CallServodRequest.method', index=3,
+      number=4, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='args', full_name='chromiumos.test.api.CallServodRequest.args', index=4,
+      number=5, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+    _CALLSERVODREQUEST_METHOD,
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1341,
+  serialized_end=1612,
+)
+
+
+_CALLSERVODRESPONSE_SUCCESS = _descriptor.Descriptor(
+  name='Success',
+  full_name='chromiumos.test.api.CallServodResponse.Success',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='result', full_name='chromiumos.test.api.CallServodResponse.Success.result', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1773,
+  serialized_end=1840,
+)
+
+_CALLSERVODRESPONSE_FAILURE = _descriptor.Descriptor(
+  name='Failure',
+  full_name='chromiumos.test.api.CallServodResponse.Failure',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='error_message', full_name='chromiumos.test.api.CallServodResponse.Failure.error_message', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=596,
+  serialized_end=628,
+)
+
+_CALLSERVODRESPONSE = _descriptor.Descriptor(
+  name='CallServodResponse',
+  full_name='chromiumos.test.api.CallServodResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='success', full_name='chromiumos.test.api.CallServodResponse.success', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='failure', full_name='chromiumos.test.api.CallServodResponse.failure', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[_CALLSERVODRESPONSE_SUCCESS, _CALLSERVODRESPONSE_FAILURE, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+    _descriptor.OneofDescriptor(
+      name='result', full_name='chromiumos.test.api.CallServodResponse.result',
+      index=0, containing_type=None, fields=[]),
+  ],
+  serialized_start=1615,
+  serialized_end=1884,
+)
+
+
+_CALLSERVODMETADATA = _descriptor.Descriptor(
+  name='CallServodMetadata',
+  full_name='chromiumos.test.api.CallServodMetadata',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1886,
+  serialized_end=1906,
+)
+
+_STARTSERVODRESPONSE_SUCCESS.containing_type = _STARTSERVODRESPONSE
+_STARTSERVODRESPONSE_FAILURE.containing_type = _STARTSERVODRESPONSE
+_STARTSERVODRESPONSE.fields_by_name['success'].message_type = _STARTSERVODRESPONSE_SUCCESS
+_STARTSERVODRESPONSE.fields_by_name['failure'].message_type = _STARTSERVODRESPONSE_FAILURE
+_STARTSERVODRESPONSE.oneofs_by_name['result'].fields.append(
+  _STARTSERVODRESPONSE.fields_by_name['success'])
+_STARTSERVODRESPONSE.fields_by_name['success'].containing_oneof = _STARTSERVODRESPONSE.oneofs_by_name['result']
+_STARTSERVODRESPONSE.oneofs_by_name['result'].fields.append(
+  _STARTSERVODRESPONSE.fields_by_name['failure'])
+_STARTSERVODRESPONSE.fields_by_name['failure'].containing_oneof = _STARTSERVODRESPONSE.oneofs_by_name['result']
+_STOPSERVODRESPONSE_SUCCESS.containing_type = _STOPSERVODRESPONSE
+_STOPSERVODRESPONSE_FAILURE.containing_type = _STOPSERVODRESPONSE
+_STOPSERVODRESPONSE.fields_by_name['success'].message_type = _STOPSERVODRESPONSE_SUCCESS
+_STOPSERVODRESPONSE.fields_by_name['failure'].message_type = _STOPSERVODRESPONSE_FAILURE
+_STOPSERVODRESPONSE.oneofs_by_name['result'].fields.append(
+  _STOPSERVODRESPONSE.fields_by_name['success'])
+_STOPSERVODRESPONSE.fields_by_name['success'].containing_oneof = _STOPSERVODRESPONSE.oneofs_by_name['result']
+_STOPSERVODRESPONSE.oneofs_by_name['result'].fields.append(
+  _STOPSERVODRESPONSE.fields_by_name['failure'])
+_STOPSERVODRESPONSE.fields_by_name['failure'].containing_oneof = _STOPSERVODRESPONSE.oneofs_by_name['result']
+_EXECCMDRESPONSE_EXITINFO.containing_type = _EXECCMDRESPONSE
+_EXECCMDRESPONSE.fields_by_name['exit_info'].message_type = _EXECCMDRESPONSE_EXITINFO
+_CALLSERVODREQUEST.fields_by_name['method'].enum_type = _CALLSERVODREQUEST_METHOD
+_CALLSERVODREQUEST.fields_by_name['args'].message_type = chromiumos_dot_config_dot_api_dot_test_dot_xmlrpc_dot_xmlrpc__pb2._VALUE
+_CALLSERVODREQUEST_METHOD.containing_type = _CALLSERVODREQUEST
+_CALLSERVODRESPONSE_SUCCESS.fields_by_name['result'].message_type = chromiumos_dot_config_dot_api_dot_test_dot_xmlrpc_dot_xmlrpc__pb2._VALUE
+_CALLSERVODRESPONSE_SUCCESS.containing_type = _CALLSERVODRESPONSE
+_CALLSERVODRESPONSE_FAILURE.containing_type = _CALLSERVODRESPONSE
+_CALLSERVODRESPONSE.fields_by_name['success'].message_type = _CALLSERVODRESPONSE_SUCCESS
+_CALLSERVODRESPONSE.fields_by_name['failure'].message_type = _CALLSERVODRESPONSE_FAILURE
+_CALLSERVODRESPONSE.oneofs_by_name['result'].fields.append(
+  _CALLSERVODRESPONSE.fields_by_name['success'])
+_CALLSERVODRESPONSE.fields_by_name['success'].containing_oneof = _CALLSERVODRESPONSE.oneofs_by_name['result']
+_CALLSERVODRESPONSE.oneofs_by_name['result'].fields.append(
+  _CALLSERVODRESPONSE.fields_by_name['failure'])
+_CALLSERVODRESPONSE.fields_by_name['failure'].containing_oneof = _CALLSERVODRESPONSE.oneofs_by_name['result']
+DESCRIPTOR.message_types_by_name['StartServodRequest'] = _STARTSERVODREQUEST
+DESCRIPTOR.message_types_by_name['StartServodResponse'] = _STARTSERVODRESPONSE
+DESCRIPTOR.message_types_by_name['StartServodMetadata'] = _STARTSERVODMETADATA
+DESCRIPTOR.message_types_by_name['StopServodRequest'] = _STOPSERVODREQUEST
+DESCRIPTOR.message_types_by_name['StopServodResponse'] = _STOPSERVODRESPONSE
+DESCRIPTOR.message_types_by_name['StopServodMetadata'] = _STOPSERVODMETADATA
+DESCRIPTOR.message_types_by_name['ExecCmdRequest'] = _EXECCMDREQUEST
+DESCRIPTOR.message_types_by_name['ExecCmdResponse'] = _EXECCMDRESPONSE
+DESCRIPTOR.message_types_by_name['ExecCmdMetadata'] = _EXECCMDMETADATA
+DESCRIPTOR.message_types_by_name['CallServodRequest'] = _CALLSERVODREQUEST
+DESCRIPTOR.message_types_by_name['CallServodResponse'] = _CALLSERVODRESPONSE
+DESCRIPTOR.message_types_by_name['CallServodMetadata'] = _CALLSERVODMETADATA
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+StartServodRequest = _reflection.GeneratedProtocolMessageType('StartServodRequest', (_message.Message,), {
+  'DESCRIPTOR' : _STARTSERVODREQUEST,
+  '__module__' : 'chromiumos.test.api.servod_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.StartServodRequest)
+  })
+_sym_db.RegisterMessage(StartServodRequest)
+
+StartServodResponse = _reflection.GeneratedProtocolMessageType('StartServodResponse', (_message.Message,), {
+
+  'Success' : _reflection.GeneratedProtocolMessageType('Success', (_message.Message,), {
+    'DESCRIPTOR' : _STARTSERVODRESPONSE_SUCCESS,
+    '__module__' : 'chromiumos.test.api.servod_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.StartServodResponse.Success)
+    })
+  ,
+
+  'Failure' : _reflection.GeneratedProtocolMessageType('Failure', (_message.Message,), {
+    'DESCRIPTOR' : _STARTSERVODRESPONSE_FAILURE,
+    '__module__' : 'chromiumos.test.api.servod_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.StartServodResponse.Failure)
+    })
+  ,
+  'DESCRIPTOR' : _STARTSERVODRESPONSE,
+  '__module__' : 'chromiumos.test.api.servod_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.StartServodResponse)
+  })
+_sym_db.RegisterMessage(StartServodResponse)
+_sym_db.RegisterMessage(StartServodResponse.Success)
+_sym_db.RegisterMessage(StartServodResponse.Failure)
+
+StartServodMetadata = _reflection.GeneratedProtocolMessageType('StartServodMetadata', (_message.Message,), {
+  'DESCRIPTOR' : _STARTSERVODMETADATA,
+  '__module__' : 'chromiumos.test.api.servod_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.StartServodMetadata)
+  })
+_sym_db.RegisterMessage(StartServodMetadata)
+
+StopServodRequest = _reflection.GeneratedProtocolMessageType('StopServodRequest', (_message.Message,), {
+  'DESCRIPTOR' : _STOPSERVODREQUEST,
+  '__module__' : 'chromiumos.test.api.servod_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.StopServodRequest)
+  })
+_sym_db.RegisterMessage(StopServodRequest)
+
+StopServodResponse = _reflection.GeneratedProtocolMessageType('StopServodResponse', (_message.Message,), {
+
+  'Success' : _reflection.GeneratedProtocolMessageType('Success', (_message.Message,), {
+    'DESCRIPTOR' : _STOPSERVODRESPONSE_SUCCESS,
+    '__module__' : 'chromiumos.test.api.servod_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.StopServodResponse.Success)
+    })
+  ,
+
+  'Failure' : _reflection.GeneratedProtocolMessageType('Failure', (_message.Message,), {
+    'DESCRIPTOR' : _STOPSERVODRESPONSE_FAILURE,
+    '__module__' : 'chromiumos.test.api.servod_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.StopServodResponse.Failure)
+    })
+  ,
+  'DESCRIPTOR' : _STOPSERVODRESPONSE,
+  '__module__' : 'chromiumos.test.api.servod_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.StopServodResponse)
+  })
+_sym_db.RegisterMessage(StopServodResponse)
+_sym_db.RegisterMessage(StopServodResponse.Success)
+_sym_db.RegisterMessage(StopServodResponse.Failure)
+
+StopServodMetadata = _reflection.GeneratedProtocolMessageType('StopServodMetadata', (_message.Message,), {
+  'DESCRIPTOR' : _STOPSERVODMETADATA,
+  '__module__' : 'chromiumos.test.api.servod_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.StopServodMetadata)
+  })
+_sym_db.RegisterMessage(StopServodMetadata)
+
+ExecCmdRequest = _reflection.GeneratedProtocolMessageType('ExecCmdRequest', (_message.Message,), {
+  'DESCRIPTOR' : _EXECCMDREQUEST,
+  '__module__' : 'chromiumos.test.api.servod_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.ExecCmdRequest)
+  })
+_sym_db.RegisterMessage(ExecCmdRequest)
+
+ExecCmdResponse = _reflection.GeneratedProtocolMessageType('ExecCmdResponse', (_message.Message,), {
+
+  'ExitInfo' : _reflection.GeneratedProtocolMessageType('ExitInfo', (_message.Message,), {
+    'DESCRIPTOR' : _EXECCMDRESPONSE_EXITINFO,
+    '__module__' : 'chromiumos.test.api.servod_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.ExecCmdResponse.ExitInfo)
+    })
+  ,
+  'DESCRIPTOR' : _EXECCMDRESPONSE,
+  '__module__' : 'chromiumos.test.api.servod_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.ExecCmdResponse)
+  })
+_sym_db.RegisterMessage(ExecCmdResponse)
+_sym_db.RegisterMessage(ExecCmdResponse.ExitInfo)
+
+ExecCmdMetadata = _reflection.GeneratedProtocolMessageType('ExecCmdMetadata', (_message.Message,), {
+  'DESCRIPTOR' : _EXECCMDMETADATA,
+  '__module__' : 'chromiumos.test.api.servod_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.ExecCmdMetadata)
+  })
+_sym_db.RegisterMessage(ExecCmdMetadata)
+
+CallServodRequest = _reflection.GeneratedProtocolMessageType('CallServodRequest', (_message.Message,), {
+  'DESCRIPTOR' : _CALLSERVODREQUEST,
+  '__module__' : 'chromiumos.test.api.servod_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.CallServodRequest)
+  })
+_sym_db.RegisterMessage(CallServodRequest)
+
+CallServodResponse = _reflection.GeneratedProtocolMessageType('CallServodResponse', (_message.Message,), {
+
+  'Success' : _reflection.GeneratedProtocolMessageType('Success', (_message.Message,), {
+    'DESCRIPTOR' : _CALLSERVODRESPONSE_SUCCESS,
+    '__module__' : 'chromiumos.test.api.servod_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.CallServodResponse.Success)
+    })
+  ,
+
+  'Failure' : _reflection.GeneratedProtocolMessageType('Failure', (_message.Message,), {
+    'DESCRIPTOR' : _CALLSERVODRESPONSE_FAILURE,
+    '__module__' : 'chromiumos.test.api.servod_service_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.CallServodResponse.Failure)
+    })
+  ,
+  'DESCRIPTOR' : _CALLSERVODRESPONSE,
+  '__module__' : 'chromiumos.test.api.servod_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.CallServodResponse)
+  })
+_sym_db.RegisterMessage(CallServodResponse)
+_sym_db.RegisterMessage(CallServodResponse.Success)
+_sym_db.RegisterMessage(CallServodResponse.Failure)
+
+CallServodMetadata = _reflection.GeneratedProtocolMessageType('CallServodMetadata', (_message.Message,), {
+  'DESCRIPTOR' : _CALLSERVODMETADATA,
+  '__module__' : 'chromiumos.test.api.servod_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.CallServodMetadata)
+  })
+_sym_db.RegisterMessage(CallServodMetadata)
+
+
+DESCRIPTOR._options = None
+
+_SERVODSERVICE = _descriptor.ServiceDescriptor(
+  name='ServodService',
+  full_name='chromiumos.test.api.ServodService',
+  file=DESCRIPTOR,
+  index=0,
+  serialized_options=None,
+  serialized_start=1909,
+  serialized_end=2379,
+  methods=[
+  _descriptor.MethodDescriptor(
+    name='StartServod',
+    full_name='chromiumos.test.api.ServodService.StartServod',
+    index=0,
+    containing_service=None,
+    input_type=_STARTSERVODREQUEST,
+    output_type=chromiumos_dot_longrunning_dot_operations__pb2._OPERATION,
+    serialized_options=b'\322A*\n\023StartServodResponse\022\023StartServodMetadata',
+  ),
+  _descriptor.MethodDescriptor(
+    name='StopServod',
+    full_name='chromiumos.test.api.ServodService.StopServod',
+    index=1,
+    containing_service=None,
+    input_type=_STOPSERVODREQUEST,
+    output_type=chromiumos_dot_longrunning_dot_operations__pb2._OPERATION,
+    serialized_options=b'\322A(\n\022StopServodResponse\022\022StopServodMetadata',
+  ),
+  _descriptor.MethodDescriptor(
+    name='ExecCmd',
+    full_name='chromiumos.test.api.ServodService.ExecCmd',
+    index=2,
+    containing_service=None,
+    input_type=_EXECCMDREQUEST,
+    output_type=_EXECCMDRESPONSE,
+    serialized_options=None,
+  ),
+  _descriptor.MethodDescriptor(
+    name='CallServod',
+    full_name='chromiumos.test.api.ServodService.CallServod',
+    index=3,
+    containing_service=None,
+    input_type=_CALLSERVODREQUEST,
+    output_type=_CALLSERVODRESPONSE,
+    serialized_options=None,
+  ),
+])
+_sym_db.RegisterServiceDescriptor(_SERVODSERVICE)
+
+DESCRIPTOR.services_by_name['ServodService'] = _SERVODSERVICE
+
+# @@protoc_insertion_point(module_scope)
diff --git a/api/gen_sdk/chromiumos/test/api/test_harness_pb2.py b/api/gen_sdk/chromiumos/test/api/test_harness_pb2.py
index 709705a..0b9eac5 100644
--- a/api/gen_sdk/chromiumos/test/api/test_harness_pb2.py
+++ b/api/gen_sdk/chromiumos/test/api/test_harness_pb2.py
@@ -18,7 +18,7 @@
   package='chromiumos.test.api',
   syntax='proto3',
   serialized_options=b'Z-go.chromium.org/chromiumos/config/go/test/api',
-  serialized_pb=b'\n&chromiumos/test/api/test_harness.proto\x12\x13\x63hromiumos.test.api\"\xaa\x02\n\x0bTestHarness\x12\x39\n\x06manual\x18\x01 \x01(\x0b\x32\'.chromiumos.test.api.TestHarness.ManualH\x00\x12\x37\n\x05tauto\x18\x02 \x01(\x0b\x32&.chromiumos.test.api.TestHarness.TautoH\x00\x12\x35\n\x04tast\x18\x03 \x01(\x0b\x32%.chromiumos.test.api.TestHarness.TastH\x00\x12\x37\n\x05gtest\x18\x04 \x01(\x0b\x32&.chromiumos.test.api.TestHarness.GtestH\x00\x1a\x08\n\x06Manual\x1a\x06\n\x04Tast\x1a\x07\n\x05Tauto\x1a\x07\n\x05GtestB\x13\n\x11test_harness_typeB/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
+  serialized_pb=b'\n&chromiumos/test/api/test_harness.proto\x12\x13\x63hromiumos.test.api\"\xc7\x02\n\x0bTestHarness\x12\x39\n\x06manual\x18\x01 \x01(\x0b\x32\'.chromiumos.test.api.TestHarness.ManualH\x00\x12\x37\n\x05tauto\x18\x02 \x01(\x0b\x32&.chromiumos.test.api.TestHarness.TautoH\x00\x12\x35\n\x04tast\x18\x03 \x01(\x0b\x32%.chromiumos.test.api.TestHarness.TastH\x00\x12\x37\n\x05gtest\x18\x04 \x01(\x0b\x32&.chromiumos.test.api.TestHarness.GtestH\x00\x1a\x08\n\x06Manual\x1a\x06\n\x04Tast\x1a\x07\n\x05Tauto\x1a$\n\x05Gtest\x12\x1b\n\x13target_bin_location\x18\x01 \x01(\tB\x13\n\x11test_harness_typeB/Z-go.chromium.org/chromiumos/config/go/test/apib\x06proto3'
 )
 
 
@@ -100,6 +100,13 @@
   file=DESCRIPTOR,
   containing_type=None,
   fields=[
+    _descriptor.FieldDescriptor(
+      name='target_bin_location', full_name='chromiumos.test.api.TestHarness.Gtest.target_bin_location', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -113,7 +120,7 @@
   oneofs=[
   ],
   serialized_start=334,
-  serialized_end=341,
+  serialized_end=370,
 )
 
 _TESTHARNESS = _descriptor.Descriptor(
@@ -167,7 +174,7 @@
       index=0, containing_type=None, fields=[]),
   ],
   serialized_start=64,
-  serialized_end=362,
+  serialized_end=391,
 )
 
 _TESTHARNESS_MANUAL.containing_type = _TESTHARNESS
diff --git a/api/gen_sdk/chromiumos/test/api/v1/__init__.py b/api/gen_sdk/chromiumos/test/api/v1/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/api/gen_sdk/chromiumos/test/api/v1/__init__.py
diff --git a/api/gen_sdk/chromiumos/test/api/v1/plan_pb2.py b/api/gen_sdk/chromiumos/test/api/v1/plan_pb2.py
new file mode 100644
index 0000000..8ff5dfc
--- /dev/null
+++ b/api/gen_sdk/chromiumos/test/api/v1/plan_pb2.py
@@ -0,0 +1,119 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: chromiumos/test/api/v1/plan.proto
+
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from chromite.api.gen_sdk.chromiumos.test.api import coverage_rule_pb2 as chromiumos_dot_test_dot_api_dot_coverage__rule__pb2
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='chromiumos/test/api/v1/plan.proto',
+  package='chromiumos.test.api.v1',
+  syntax='proto3',
+  serialized_options=b'Z<go.chromium.org/chromiumos/config/go/test/api/v1;test_api_v1',
+  serialized_pb=b'\n!chromiumos/test/api/v1/plan.proto\x12\x16\x63hromiumos.test.api.v1\x1a\'chromiumos/test/api/coverage_rule.proto\"\x9f\x01\n\nHWTestPlan\x12\x39\n\x02id\x18\x01 \x01(\x0b\x32-.chromiumos.test.api.v1.HWTestPlan.TestPlanId\x12\x39\n\x0e\x63overage_rules\x18\x02 \x03(\x0b\x32!.chromiumos.test.api.CoverageRule\x1a\x1b\n\nTestPlanId\x12\r\n\x05value\x18\x01 \x01(\tB>Z<go.chromium.org/chromiumos/config/go/test/api/v1;test_api_v1b\x06proto3'
+  ,
+  dependencies=[chromiumos_dot_test_dot_api_dot_coverage__rule__pb2.DESCRIPTOR,])
+
+
+
+
+_HWTESTPLAN_TESTPLANID = _descriptor.Descriptor(
+  name='TestPlanId',
+  full_name='chromiumos.test.api.v1.HWTestPlan.TestPlanId',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='value', full_name='chromiumos.test.api.v1.HWTestPlan.TestPlanId.value', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=235,
+  serialized_end=262,
+)
+
+_HWTESTPLAN = _descriptor.Descriptor(
+  name='HWTestPlan',
+  full_name='chromiumos.test.api.v1.HWTestPlan',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='id', full_name='chromiumos.test.api.v1.HWTestPlan.id', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='coverage_rules', full_name='chromiumos.test.api.v1.HWTestPlan.coverage_rules', index=1,
+      number=2, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[_HWTESTPLAN_TESTPLANID, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=103,
+  serialized_end=262,
+)
+
+_HWTESTPLAN_TESTPLANID.containing_type = _HWTESTPLAN
+_HWTESTPLAN.fields_by_name['id'].message_type = _HWTESTPLAN_TESTPLANID
+_HWTESTPLAN.fields_by_name['coverage_rules'].message_type = chromiumos_dot_test_dot_api_dot_coverage__rule__pb2._COVERAGERULE
+DESCRIPTOR.message_types_by_name['HWTestPlan'] = _HWTESTPLAN
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+HWTestPlan = _reflection.GeneratedProtocolMessageType('HWTestPlan', (_message.Message,), {
+
+  'TestPlanId' : _reflection.GeneratedProtocolMessageType('TestPlanId', (_message.Message,), {
+    'DESCRIPTOR' : _HWTESTPLAN_TESTPLANID,
+    '__module__' : 'chromiumos.test.api.v1.plan_pb2'
+    # @@protoc_insertion_point(class_scope:chromiumos.test.api.v1.HWTestPlan.TestPlanId)
+    })
+  ,
+  'DESCRIPTOR' : _HWTESTPLAN,
+  '__module__' : 'chromiumos.test.api.v1.plan_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.api.v1.HWTestPlan)
+  })
+_sym_db.RegisterMessage(HWTestPlan)
+_sym_db.RegisterMessage(HWTestPlan.TestPlanId)
+
+
+DESCRIPTOR._options = None
+# @@protoc_insertion_point(module_scope)
diff --git a/api/gen_sdk/chromiumos/test/artifact/dut_metadata_artifact_pb2.py b/api/gen_sdk/chromiumos/test/artifact/dut_metadata_artifact_pb2.py
new file mode 100644
index 0000000..740c7fe
--- /dev/null
+++ b/api/gen_sdk/chromiumos/test/artifact/dut_metadata_artifact_pb2.py
@@ -0,0 +1,121 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: chromiumos/test/artifact/dut_metadata_artifact.proto
+
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from chromite.api.gen_sdk.chromiumos.test.api import provision_state_pb2 as chromiumos_dot_test_dot_api_dot_provision__state__pb2
+from chromite.api.gen_sdk.chromiumos.test.lab.api import dut_pb2 as chromiumos_dot_test_dot_lab_dot_api_dot_dut__pb2
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='chromiumos/test/artifact/dut_metadata_artifact.proto',
+  package='chromiumos.test.artifact',
+  syntax='proto3',
+  serialized_options=b'Z2go.chromium.org/chromiumos/config/go/test/artifact',
+  serialized_pb=b'\n4chromiumos/test/artifact/dut_metadata_artifact.proto\x12\x18\x63hromiumos.test.artifact\x1a)chromiumos/test/api/provision_state.proto\x1a!chromiumos/test/lab/api/dut.proto\"\\\n\x13\x44utMetadataArtifact\x12\x45\n\x12\x64ut_info_artifacts\x18\x01 \x03(\x0b\x32).chromiumos.test.artifact.DutInfoArtifact\"z\n\x0f\x44utInfoArtifact\x12)\n\x03\x64ut\x18\x01 \x01(\x0b\x32\x1c.chromiumos.test.lab.api.Dut\x12<\n\x0fprovision_state\x18\x02 \x01(\x0b\x32#.chromiumos.test.api.ProvisionStateB4Z2go.chromium.org/chromiumos/config/go/test/artifactb\x06proto3'
+  ,
+  dependencies=[chromiumos_dot_test_dot_api_dot_provision__state__pb2.DESCRIPTOR,chromiumos_dot_test_dot_lab_dot_api_dot_dut__pb2.DESCRIPTOR,])
+
+
+
+
+_DUTMETADATAARTIFACT = _descriptor.Descriptor(
+  name='DutMetadataArtifact',
+  full_name='chromiumos.test.artifact.DutMetadataArtifact',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='dut_info_artifacts', full_name='chromiumos.test.artifact.DutMetadataArtifact.dut_info_artifacts', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=160,
+  serialized_end=252,
+)
+
+
+_DUTINFOARTIFACT = _descriptor.Descriptor(
+  name='DutInfoArtifact',
+  full_name='chromiumos.test.artifact.DutInfoArtifact',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='dut', full_name='chromiumos.test.artifact.DutInfoArtifact.dut', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='provision_state', full_name='chromiumos.test.artifact.DutInfoArtifact.provision_state', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=254,
+  serialized_end=376,
+)
+
+_DUTMETADATAARTIFACT.fields_by_name['dut_info_artifacts'].message_type = _DUTINFOARTIFACT
+_DUTINFOARTIFACT.fields_by_name['dut'].message_type = chromiumos_dot_test_dot_lab_dot_api_dot_dut__pb2._DUT
+_DUTINFOARTIFACT.fields_by_name['provision_state'].message_type = chromiumos_dot_test_dot_api_dot_provision__state__pb2._PROVISIONSTATE
+DESCRIPTOR.message_types_by_name['DutMetadataArtifact'] = _DUTMETADATAARTIFACT
+DESCRIPTOR.message_types_by_name['DutInfoArtifact'] = _DUTINFOARTIFACT
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+DutMetadataArtifact = _reflection.GeneratedProtocolMessageType('DutMetadataArtifact', (_message.Message,), {
+  'DESCRIPTOR' : _DUTMETADATAARTIFACT,
+  '__module__' : 'chromiumos.test.artifact.dut_metadata_artifact_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.artifact.DutMetadataArtifact)
+  })
+_sym_db.RegisterMessage(DutMetadataArtifact)
+
+DutInfoArtifact = _reflection.GeneratedProtocolMessageType('DutInfoArtifact', (_message.Message,), {
+  'DESCRIPTOR' : _DUTINFOARTIFACT,
+  '__module__' : 'chromiumos.test.artifact.dut_metadata_artifact_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.artifact.DutInfoArtifact)
+  })
+_sym_db.RegisterMessage(DutInfoArtifact)
+
+
+DESCRIPTOR._options = None
+# @@protoc_insertion_point(module_scope)
diff --git a/api/gen_sdk/chromiumos/test/artifact/manifest_pb2.py b/api/gen_sdk/chromiumos/test/artifact/manifest_pb2.py
index d2e1469..8897b95 100644
--- a/api/gen_sdk/chromiumos/test/artifact/manifest_pb2.py
+++ b/api/gen_sdk/chromiumos/test/artifact/manifest_pb2.py
@@ -11,6 +11,7 @@
 _sym_db = _symbol_database.Default()
 
 
+from chromite.api.gen_sdk.chromiumos import storage_path_pb2 as chromiumos_dot_storage__path__pb2
 
 
 DESCRIPTOR = _descriptor.FileDescriptor(
@@ -18,8 +19,9 @@
   package='chromiumos.test.artifact',
   syntax='proto3',
   serialized_options=b'Z2go.chromium.org/chromiumos/config/go/test/artifact',
-  serialized_pb=b'\n\'chromiumos/test/artifact/manifest.proto\x12\x18\x63hromiumos.test.artifact\"R\n\x08Manifest\x12\x0f\n\x07version\x18\x01 \x01(\r\x12\x35\n\tartifacts\x18\x02 \x03(\x0b\x32\".chromiumos.test.artifact.Artifact\"\x99\x01\n\x08\x41rtifact\x12=\n\x04type\x18\x01 \x01(\x0e\x32/.chromiumos.test.artifact.Artifact.ArtifactType\x12\x0e\n\x06gs_url\x18\x02 \x01(\t\">\n\x0c\x41rtifactType\x12\x1d\n\x19\x41RTIFACT_TYPE_UNSPECIFIED\x10\x00\x12\x0f\n\x0bTEST_RESULT\x10\x01\x42\x34Z2go.chromium.org/chromiumos/config/go/test/artifactb\x06proto3'
-)
+  serialized_pb=b'\n\'chromiumos/test/artifact/manifest.proto\x12\x18\x63hromiumos.test.artifact\x1a\x1d\x63hromiumos/storage_path.proto\"R\n\x08Manifest\x12\x0f\n\x07version\x18\x01 \x01(\r\x12\x35\n\tartifacts\x18\x02 \x03(\x0b\x32\".chromiumos.test.artifact.Artifact\"\xd9\x01\n\x08\x41rtifact\x12=\n\x04type\x18\x01 \x01(\x0e\x32/.chromiumos.test.artifact.Artifact.ArtifactType\x12-\n\x0cstorage_path\x18\x02 \x01(\x0b\x32\x17.chromiumos.StoragePath\"_\n\x0c\x41rtifactType\x12\x1d\n\x19\x41RTIFACT_TYPE_UNSPECIFIED\x10\x00\x12\x0f\n\x0bTEST_RESULT\x10\x01\x12\x10\n\x0c\x44UT_METADATA\x10\x02\x12\r\n\tTEST_PLAN\x10\x03\x42\x34Z2go.chromium.org/chromiumos/config/go/test/artifactb\x06proto3'
+  ,
+  dependencies=[chromiumos_dot_storage__path__pb2.DESCRIPTOR,])
 
 
 
@@ -37,11 +39,19 @@
       name='TEST_RESULT', index=1, number=1,
       serialized_options=None,
       type=None),
+    _descriptor.EnumValueDescriptor(
+      name='DUT_METADATA', index=2, number=2,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='TEST_PLAN', index=3, number=3,
+      serialized_options=None,
+      type=None),
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=245,
-  serialized_end=307,
+  serialized_start=307,
+  serialized_end=402,
 )
 _sym_db.RegisterEnumDescriptor(_ARTIFACT_ARTIFACTTYPE)
 
@@ -79,8 +89,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=69,
-  serialized_end=151,
+  serialized_start=100,
+  serialized_end=182,
 )
 
 
@@ -99,9 +109,9 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='gs_url', full_name='chromiumos.test.artifact.Artifact.gs_url', index=1,
-      number=2, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=b"".decode('utf-8'),
+      name='storage_path', full_name='chromiumos.test.artifact.Artifact.storage_path', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
@@ -118,12 +128,13 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=154,
-  serialized_end=307,
+  serialized_start=185,
+  serialized_end=402,
 )
 
 _MANIFEST.fields_by_name['artifacts'].message_type = _ARTIFACT
 _ARTIFACT.fields_by_name['type'].enum_type = _ARTIFACT_ARTIFACTTYPE
+_ARTIFACT.fields_by_name['storage_path'].message_type = chromiumos_dot_storage__path__pb2._STORAGEPATH
 _ARTIFACT_ARTIFACTTYPE.containing_type = _ARTIFACT
 DESCRIPTOR.message_types_by_name['Manifest'] = _MANIFEST
 DESCRIPTOR.message_types_by_name['Artifact'] = _ARTIFACT
diff --git a/api/gen_sdk/chromiumos/test/artifact/test_plan_pb2.py b/api/gen_sdk/chromiumos/test/artifact/test_plan_pb2.py
new file mode 100644
index 0000000..16b32b7
--- /dev/null
+++ b/api/gen_sdk/chromiumos/test/artifact/test_plan_pb2.py
@@ -0,0 +1,72 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: chromiumos/test/artifact/test_plan.proto
+
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from chromite.api.gen_sdk.chromiumos.test.api.v1 import plan_pb2 as chromiumos_dot_test_dot_api_dot_v1_dot_plan__pb2
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='chromiumos/test/artifact/test_plan.proto',
+  package='chromiumos.test.artifact',
+  syntax='proto3',
+  serialized_options=b'Z2go.chromium.org/chromiumos/config/go/test/artifact',
+  serialized_pb=b'\n(chromiumos/test/artifact/test_plan.proto\x12\x18\x63hromiumos.test.artifact\x1a!chromiumos/test/api/v1/plan.proto\"M\n\x10TestPlanArtifact\x12\x39\n\rhw_test_plans\x18\x01 \x03(\x0b\x32\".chromiumos.test.api.v1.HWTestPlanB4Z2go.chromium.org/chromiumos/config/go/test/artifactb\x06proto3'
+  ,
+  dependencies=[chromiumos_dot_test_dot_api_dot_v1_dot_plan__pb2.DESCRIPTOR,])
+
+
+
+
+_TESTPLANARTIFACT = _descriptor.Descriptor(
+  name='TestPlanArtifact',
+  full_name='chromiumos.test.artifact.TestPlanArtifact',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='hw_test_plans', full_name='chromiumos.test.artifact.TestPlanArtifact.hw_test_plans', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=105,
+  serialized_end=182,
+)
+
+_TESTPLANARTIFACT.fields_by_name['hw_test_plans'].message_type = chromiumos_dot_test_dot_api_dot_v1_dot_plan__pb2._HWTESTPLAN
+DESCRIPTOR.message_types_by_name['TestPlanArtifact'] = _TESTPLANARTIFACT
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+TestPlanArtifact = _reflection.GeneratedProtocolMessageType('TestPlanArtifact', (_message.Message,), {
+  'DESCRIPTOR' : _TESTPLANARTIFACT,
+  '__module__' : 'chromiumos.test.artifact.test_plan_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.artifact.TestPlanArtifact)
+  })
+_sym_db.RegisterMessage(TestPlanArtifact)
+
+
+DESCRIPTOR._options = None
+# @@protoc_insertion_point(module_scope)
diff --git a/api/gen_sdk/chromiumos/test/artifact/test_result_pb2.py b/api/gen_sdk/chromiumos/test/artifact/test_result_pb2.py
index 638a447..ae667c0 100644
--- a/api/gen_sdk/chromiumos/test/artifact/test_result_pb2.py
+++ b/api/gen_sdk/chromiumos/test/artifact/test_result_pb2.py
@@ -12,9 +12,11 @@
 
 
 from chromite.api.gen_sdk.chromiumos import storage_path_pb2 as chromiumos_dot_storage__path__pb2
+from chromite.api.gen_sdk.chromiumos.test.api import provision_state_pb2 as chromiumos_dot_test_dot_api_dot_provision__state__pb2
 from chromite.api.gen_sdk.chromiumos.test.api import test_case_pb2 as chromiumos_dot_test_dot_api_dot_test__case__pb2
 from chromite.api.gen_sdk.chromiumos.test.api import test_case_metadata_pb2 as chromiumos_dot_test_dot_api_dot_test__case__metadata__pb2
 from chromite.api.gen_sdk.chromiumos.test.api import test_case_result_pb2 as chromiumos_dot_test_dot_api_dot_test__case__result__pb2
+from chromite.api.gen_sdk.chromiumos.test.api.v1 import plan_pb2 as chromiumos_dot_test_dot_api_dot_v1_dot_plan__pb2
 from chromite.api.gen_sdk.chromiumos.test.lab.api import dut_pb2 as chromiumos_dot_test_dot_lab_dot_api_dot_dut__pb2
 
 
@@ -23,9 +25,9 @@
   package='chromiumos.test.artifact',
   syntax='proto3',
   serialized_options=b'Z2go.chromium.org/chromiumos/config/go/test/artifact',
-  serialized_pb=b'\n*chromiumos/test/artifact/test_result.proto\x12\x18\x63hromiumos.test.artifact\x1a\x1d\x63hromiumos/storage_path.proto\x1a#chromiumos/test/api/test_case.proto\x1a,chromiumos/test/api/test_case_metadata.proto\x1a*chromiumos/test/api/test_case_result.proto\x1a!chromiumos/test/lab/api/dut.proto\"\x93\x01\n\nTestResult\x12\x0f\n\x07version\x18\x01 \x01(\r\x12\x34\n\ttest_runs\x18\x02 \x03(\x0b\x32!.chromiumos.test.artifact.TestRun\x12>\n\x0e\x63ustom_results\x18\x03 \x03(\x0b\x32&.chromiumos.test.artifact.CustomResult\"\xff\x02\n\x07TestRun\x12\x30\n\ttest_case\x18\x01 \x01(\x0b\x32\x1d.chromiumos.test.api.TestCase\x12\x41\n\x12test_case_metadata\x18\x02 \x01(\x0b\x32%.chromiumos.test.api.TestCaseMetadata\x12=\n\x10test_case_result\x18\x03 \x01(\x0b\x32#.chromiumos.test.api.TestCaseResult\x12\x11\n\tbuild_ids\x18\x04 \x03(\x04\x12:\n\x0c\x64ut_topology\x18\x05 \x01(\x0b\x32$.chromiumos.test.lab.api.DutTopology\x12\x36\n\x0bprimary_dut\x18\x06 \x01(\x0b\x32!.chromiumos.test.artifact.DutInfo\x12\x39\n\x0e\x63ompanion_duts\x18\x07 \x03(\x0b\x32!.chromiumos.test.artifact.DutInfo\"\x9e\x01\n\x07\x44utInfo\x12+\n\x02id\x18\x01 \x01(\x0b\x32\x1f.chromiumos.test.lab.api.Dut.Id\x12\x39\n\x04tags\x18\x02 \x03(\x0b\x32+.chromiumos.test.artifact.DutInfo.TagsEntry\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x8a\x01\n\x0c\x43ustomResult\x12\x30\n\x0fresult_dir_path\x18\x01 \x01(\x0b\x32\x17.chromiumos.StoragePath\x12\x39\n\x03\x63ts\x18\x02 \x01(\x0b\x32*.chromiumos.test.artifact.CustomResult.CtsH\x00\x1a\x05\n\x03\x43tsB\x06\n\x04typeB4Z2go.chromium.org/chromiumos/config/go/test/artifactb\x06proto3'
+  serialized_pb=b'\n*chromiumos/test/artifact/test_result.proto\x12\x18\x63hromiumos.test.artifact\x1a\x1d\x63hromiumos/storage_path.proto\x1a)chromiumos/test/api/provision_state.proto\x1a#chromiumos/test/api/test_case.proto\x1a,chromiumos/test/api/test_case_metadata.proto\x1a*chromiumos/test/api/test_case_result.proto\x1a!chromiumos/test/api/v1/plan.proto\x1a!chromiumos/test/lab/api/dut.proto\"\xd9\x01\n\nTestResult\x12\x0f\n\x07version\x18\x01 \x01(\r\x12\x34\n\ttest_runs\x18\x02 \x03(\x0b\x32!.chromiumos.test.artifact.TestRun\x12>\n\x0e\x63ustom_results\x18\x03 \x03(\x0b\x32&.chromiumos.test.artifact.CustomResult\x12\x44\n\rtest_plan_ids\x18\x04 \x03(\x0b\x32-.chromiumos.test.api.v1.HWTestPlan.TestPlanId\"\xff\x02\n\x07TestRun\x12\x30\n\ttest_case\x18\x01 \x01(\x0b\x32\x1d.chromiumos.test.api.TestCase\x12\x41\n\x12test_case_metadata\x18\x02 \x01(\x0b\x32%.chromiumos.test.api.TestCaseMetadata\x12=\n\x10test_case_result\x18\x03 \x01(\x0b\x32#.chromiumos.test.api.TestCaseResult\x12\x11\n\tbuild_ids\x18\x04 \x03(\x04\x12:\n\x0c\x64ut_topology\x18\x05 \x01(\x0b\x32$.chromiumos.test.lab.api.DutTopology\x12\x36\n\x0bprimary_dut\x18\x06 \x01(\x0b\x32!.chromiumos.test.artifact.DutInfo\x12\x39\n\x0e\x63ompanion_duts\x18\x07 \x03(\x0b\x32!.chromiumos.test.artifact.DutInfo\"\xe2\x01\n\x07\x44utInfo\x12+\n\x02id\x18\x01 \x01(\x0b\x32\x1f.chromiumos.test.lab.api.Dut.Id\x12\x42\n\x12provision_state_id\x18\x03 \x01(\x0b\x32&.chromiumos.test.api.ProvisionState.Id\x12\x39\n\x04tags\x18\x02 \x03(\x0b\x32+.chromiumos.test.artifact.DutInfo.TagsEntry\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x8a\x01\n\x0c\x43ustomResult\x12\x30\n\x0fresult_dir_path\x18\x01 \x01(\x0b\x32\x17.chromiumos.StoragePath\x12\x39\n\x03\x63ts\x18\x02 \x01(\x0b\x32*.chromiumos.test.artifact.CustomResult.CtsH\x00\x1a\x05\n\x03\x43tsB\x06\n\x04typeB4Z2go.chromium.org/chromiumos/config/go/test/artifactb\x06proto3'
   ,
-  dependencies=[chromiumos_dot_storage__path__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_test__case__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_test__case__metadata__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_test__case__result__pb2.DESCRIPTOR,chromiumos_dot_test_dot_lab_dot_api_dot_dut__pb2.DESCRIPTOR,])
+  dependencies=[chromiumos_dot_storage__path__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_provision__state__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_test__case__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_test__case__metadata__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_test__case__result__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_v1_dot_plan__pb2.DESCRIPTOR,chromiumos_dot_test_dot_lab_dot_api_dot_dut__pb2.DESCRIPTOR,])
 
 
 
@@ -58,6 +60,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='test_plan_ids', full_name='chromiumos.test.artifact.TestResult.test_plan_ids', index=3,
+      number=4, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -70,8 +79,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=266,
-  serialized_end=413,
+  serialized_start=344,
+  serialized_end=561,
 )
 
 
@@ -143,8 +152,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=416,
-  serialized_end=799,
+  serialized_start=564,
+  serialized_end=947,
 )
 
 
@@ -181,8 +190,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=917,
-  serialized_end=960,
+  serialized_start=1133,
+  serialized_end=1176,
 )
 
 _DUTINFO = _descriptor.Descriptor(
@@ -200,7 +209,14 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='tags', full_name='chromiumos.test.artifact.DutInfo.tags', index=1,
+      name='provision_state_id', full_name='chromiumos.test.artifact.DutInfo.provision_state_id', index=1,
+      number=3, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='tags', full_name='chromiumos.test.artifact.DutInfo.tags', index=2,
       number=2, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
@@ -218,8 +234,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=802,
-  serialized_end=960,
+  serialized_start=950,
+  serialized_end=1176,
 )
 
 
@@ -242,8 +258,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1088,
-  serialized_end=1093,
+  serialized_start=1304,
+  serialized_end=1309,
 )
 
 _CUSTOMRESULT = _descriptor.Descriptor(
@@ -282,12 +298,13 @@
       name='type', full_name='chromiumos.test.artifact.CustomResult.type',
       index=0, containing_type=None, fields=[]),
   ],
-  serialized_start=963,
-  serialized_end=1101,
+  serialized_start=1179,
+  serialized_end=1317,
 )
 
 _TESTRESULT.fields_by_name['test_runs'].message_type = _TESTRUN
 _TESTRESULT.fields_by_name['custom_results'].message_type = _CUSTOMRESULT
+_TESTRESULT.fields_by_name['test_plan_ids'].message_type = chromiumos_dot_test_dot_api_dot_v1_dot_plan__pb2._HWTESTPLAN_TESTPLANID
 _TESTRUN.fields_by_name['test_case'].message_type = chromiumos_dot_test_dot_api_dot_test__case__pb2._TESTCASE
 _TESTRUN.fields_by_name['test_case_metadata'].message_type = chromiumos_dot_test_dot_api_dot_test__case__metadata__pb2._TESTCASEMETADATA
 _TESTRUN.fields_by_name['test_case_result'].message_type = chromiumos_dot_test_dot_api_dot_test__case__result__pb2._TESTCASERESULT
@@ -296,6 +313,7 @@
 _TESTRUN.fields_by_name['companion_duts'].message_type = _DUTINFO
 _DUTINFO_TAGSENTRY.containing_type = _DUTINFO
 _DUTINFO.fields_by_name['id'].message_type = chromiumos_dot_test_dot_lab_dot_api_dot_dut__pb2._DUT_ID
+_DUTINFO.fields_by_name['provision_state_id'].message_type = chromiumos_dot_test_dot_api_dot_provision__state__pb2._PROVISIONSTATE_ID
 _DUTINFO.fields_by_name['tags'].message_type = _DUTINFO_TAGSENTRY
 _CUSTOMRESULT_CTS.containing_type = _CUSTOMRESULT
 _CUSTOMRESULT.fields_by_name['result_dir_path'].message_type = chromiumos_dot_storage__path__pb2._STORAGEPATH
diff --git a/api/gen_sdk/chromiumos/test/lab/api/dut_pb2.py b/api/gen_sdk/chromiumos/test/lab/api/dut_pb2.py
index 2234897..1920f3a 100644
--- a/api/gen_sdk/chromiumos/test/lab/api/dut_pb2.py
+++ b/api/gen_sdk/chromiumos/test/lab/api/dut_pb2.py
@@ -20,7 +20,7 @@
   package='chromiumos.test.lab.api',
   syntax='proto3',
   serialized_options=b'Z1go.chromium.org/chromiumos/config/go/test/lab/api',
-  serialized_pb=b'\n!chromiumos/test/lab/api/dut.proto\x12\x17\x63hromiumos.test.lab.api\x1a,chromiumos/config/api/device_config_id.proto\x1a)chromiumos/test/lab/api/ip_endpoint.proto\"\x8f\x07\n\x03\x44ut\x12+\n\x02id\x18\x01 \x01(\x0b\x32\x1f.chromiumos.test.lab.api.Dut.Id\x12\x39\n\x08\x63hromeos\x18\x02 \x01(\x0b\x32%.chromiumos.test.lab.api.Dut.ChromeOSH\x00\x12\x37\n\x07\x61ndroid\x18\x03 \x01(\x0b\x32$.chromiumos.test.lab.api.Dut.AndroidH\x00\x12:\n\x0c\x63\x61\x63he_server\x18\x0e \x01(\x0b\x32$.chromiumos.test.lab.api.CacheServer\x1a\x13\n\x02Id\x12\r\n\x05value\x18\x01 \x01(\t\x1a\xfe\x04\n\x08\x43hromeOS\x12?\n\x10\x64\x65vice_config_id\x18\x03 \x01(\x0b\x32%.chromiumos.config.api.DeviceConfigId\x12\x30\n\x03ssh\x18\x02 \x01(\x0b\x32#.chromiumos.test.lab.api.IpEndpoint\x12-\n\x05servo\x18\x04 \x01(\x0b\x32\x1e.chromiumos.test.lab.api.Servo\x12\x35\n\tchameleon\x18\x05 \x01(\x0b\x32\".chromiumos.test.lab.api.Chameleon\x12)\n\x03rpm\x18\x06 \x01(\x0b\x32\x1c.chromiumos.test.lab.api.RPM\x12\x41\n\x10\x65xternal_cameras\x18\x07 \x03(\x0b\x32\'.chromiumos.test.lab.api.ExternalCamera\x12-\n\x05\x61udio\x18\x08 \x01(\x0b\x32\x1e.chromiumos.test.lab.api.Audio\x12+\n\x04wifi\x18\t \x01(\x0b\x32\x1d.chromiumos.test.lab.api.Wifi\x12-\n\x05touch\x18\n \x01(\x0b\x32\x1e.chromiumos.test.lab.api.Touch\x12\x35\n\tcamerabox\x18\x0b \x01(\x0b\x32\".chromiumos.test.lab.api.Camerabox\x12.\n\x06\x63\x61\x62les\x18\x0c \x03(\x0b\x32\x1e.chromiumos.test.lab.api.Cable\x12\x33\n\x08\x63\x65llular\x18\r \x01(\x0b\x32!.chromiumos.test.lab.api.CellularJ\x04\x08\x01\x10\x02\x1a\t\n\x07\x41ndroidB\n\n\x08\x64ut_type\"\x8f\x01\n\x0b\x44utTopology\x12\x33\n\x02id\x18\x03 \x01(\x0b\x32\'.chromiumos.test.lab.api.DutTopology.Id\x12*\n\x04\x64uts\x18\x04 \x03(\x0b\x32\x1c.chromiumos.test.lab.api.Dut\x1a\x13\n\x02Id\x12\r\n\x05value\x18\x01 \x01(\tJ\x04\x08\x01\x10\x02J\x04\x08\x02\x10\x03\")\n\x05\x41udio\x12\x11\n\taudio_box\x18\x01 \x01(\x08\x12\r\n\x05\x61trus\x18\x02 \x01(\x08\"\x95\x01\n\x05\x43\x61\x62le\x12\x31\n\x04type\x18\x01 \x01(\x0e\x32#.chromiumos.test.lab.api.Cable.Type\"Y\n\x04Type\x12\x14\n\x10TYPE_UNSPECIFIED\x10\x00\x12\r\n\tAUDIOJACK\x10\x01\x12\x0c\n\x08USBAUDIO\x10\x02\x12\x0f\n\x0bUSBPRINTING\x10\x03\x12\r\n\tHDMIAUDIO\x10\x04\"C\n\x0b\x43\x61\x63heServer\x12\x34\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0b\x32#.chromiumos.test.lab.api.IpEndpoint\"}\n\tCamerabox\x12\x39\n\x06\x66\x61\x63ing\x18\x01 \x01(\x0e\x32).chromiumos.test.lab.api.Camerabox.Facing\"5\n\x06\x46\x61\x63ing\x12\x16\n\x12\x46\x41\x43ING_UNSPECIFIED\x10\x00\x12\x08\n\x04\x42\x41\x43K\x10\x01\x12\t\n\x05\x46RONT\x10\x02\"\x92\x01\n\x08\x43\x65llular\x12=\n\toperators\x18\x01 \x03(\x0e\x32*.chromiumos.test.lab.api.Cellular.Operator\"G\n\x08Operator\x12\x18\n\x14OPERATOR_UNSPECIFIED\x10\x00\x12\x07\n\x03\x41TT\x10\x01\x12\x0b\n\x07VERIZON\x10\x02\x12\x0b\n\x07TMOBILE\x10\x03\"\xf2\x01\n\tChameleon\x12\x42\n\x0bperipherals\x18\x01 \x03(\x0e\x32-.chromiumos.test.lab.api.Chameleon.Peripheral\x12\x13\n\x0b\x61udio_board\x18\x02 \x01(\x08\"\x8b\x01\n\nPeripheral\x12\x1a\n\x16PREIPHERAL_UNSPECIFIED\x10\x00\x12\n\n\x06\x42T_HID\x10\x01\x12\x06\n\x02\x44P\x10\x02\x12\x0b\n\x07\x44P_HDMI\x10\x03\x12\x07\n\x03VGA\x10\x04\x12\x08\n\x04HDMI\x10\x05\x12\x0e\n\nBT_BLE_HID\x10\x06\x12\x10\n\x0c\x42T_A2DP_SINK\x10\x07\x12\x0b\n\x07\x42T_PEER\x10\x08\"\x83\x01\n\x0e\x45xternalCamera\x12:\n\x04type\x18\x01 \x01(\x0e\x32,.chromiumos.test.lab.api.ExternalCamera.Type\"5\n\x04Type\x12\x14\n\x10TYPE_UNSPECIFIED\x10\x00\x12\n\n\x06HUDDLY\x10\x01\x12\x0b\n\x07PTZPRO2\x10\x02\"\x16\n\x03RPM\x12\x0f\n\x07present\x18\x01 \x01(\x08\"U\n\x05Servo\x12\x0f\n\x07present\x18\x01 \x01(\x08\x12;\n\x0eservod_address\x18\x02 \x01(\x0b\x32#.chromiumos.test.lab.api.IpEndpoint\"\x15\n\x05Touch\x12\x0c\n\x04mimo\x18\x01 \x01(\x08\"\xe6\x01\n\x04Wifi\x12>\n\x0b\x65nvironment\x18\x01 \x01(\x0e\x32).chromiumos.test.lab.api.Wifi.Environment\x12\x35\n\x07\x61ntenna\x18\x02 \x01(\x0b\x32$.chromiumos.test.lab.api.WifiAntenna\"g\n\x0b\x45nvironment\x12\x1b\n\x17\x45NVIRONMENT_UNSPECIFIED\x10\x00\x12\x0c\n\x08STANDARD\x10\x01\x12\r\n\tWIFI_CELL\x10\x02\x12\t\n\x05\x43HAOS\x10\x03\x12\x13\n\x0fROUTER_802_11AX\x10\x04\"\x95\x01\n\x0bWifiAntenna\x12\x43\n\nconnection\x18\x01 \x01(\x0e\x32/.chromiumos.test.lab.api.WifiAntenna.Connection\"A\n\nConnection\x12\x1a\n\x16\x43ONNECTION_UNSPECIFIED\x10\x00\x12\x0e\n\nCONDUCTIVE\x10\x01\x12\x07\n\x03OTA\x10\x02\x42\x33Z1go.chromium.org/chromiumos/config/go/test/lab/apib\x06proto3'
+  serialized_pb=b'\n!chromiumos/test/lab/api/dut.proto\x12\x17\x63hromiumos.test.lab.api\x1a,chromiumos/config/api/device_config_id.proto\x1a)chromiumos/test/lab/api/ip_endpoint.proto\"\xe3\x08\n\x03\x44ut\x12+\n\x02id\x18\x01 \x01(\x0b\x32\x1f.chromiumos.test.lab.api.Dut.Id\x12\x39\n\x08\x63hromeos\x18\x02 \x01(\x0b\x32%.chromiumos.test.lab.api.Dut.ChromeOSH\x00\x12\x37\n\x07\x61ndroid\x18\x03 \x01(\x0b\x32$.chromiumos.test.lab.api.Dut.AndroidH\x00\x12:\n\x0c\x63\x61\x63he_server\x18\x04 \x01(\x0b\x32$.chromiumos.test.lab.api.CacheServer\x1a\x13\n\x02Id\x12\r\n\x05value\x18\x01 \x01(\t\x1a\xb4\x05\n\x08\x43hromeOS\x12?\n\x10\x64\x65vice_config_id\x18\x03 \x01(\x0b\x32%.chromiumos.config.api.DeviceConfigId\x12\x30\n\x03ssh\x18\x02 \x01(\x0b\x32#.chromiumos.test.lab.api.IpEndpoint\x12\x34\n\tdut_model\x18\x0e \x01(\x0b\x32!.chromiumos.test.lab.api.DutModel\x12-\n\x05servo\x18\x04 \x01(\x0b\x32\x1e.chromiumos.test.lab.api.Servo\x12\x35\n\tchameleon\x18\x05 \x01(\x0b\x32\".chromiumos.test.lab.api.Chameleon\x12)\n\x03rpm\x18\x06 \x01(\x0b\x32\x1c.chromiumos.test.lab.api.RPM\x12\x41\n\x10\x65xternal_cameras\x18\x07 \x03(\x0b\x32\'.chromiumos.test.lab.api.ExternalCamera\x12-\n\x05\x61udio\x18\x08 \x01(\x0b\x32\x1e.chromiumos.test.lab.api.Audio\x12+\n\x04wifi\x18\t \x01(\x0b\x32\x1d.chromiumos.test.lab.api.Wifi\x12-\n\x05touch\x18\n \x01(\x0b\x32\x1e.chromiumos.test.lab.api.Touch\x12\x35\n\tcamerabox\x18\x0b \x01(\x0b\x32\".chromiumos.test.lab.api.Camerabox\x12.\n\x06\x63\x61\x62les\x18\x0c \x03(\x0b\x32\x1e.chromiumos.test.lab.api.Cable\x12\x33\n\x08\x63\x65llular\x18\r \x01(\x0b\x32!.chromiumos.test.lab.api.CellularJ\x04\x08\x01\x10\x02\x1a\xa6\x01\n\x07\x41ndroid\x12@\n\x13\x61ssociated_hostname\x18\x01 \x01(\x0b\x32#.chromiumos.test.lab.api.IpEndpoint\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x15\n\rserial_number\x18\x03 \x01(\t\x12\x34\n\tdut_model\x18\x04 \x01(\x0b\x32!.chromiumos.test.lab.api.DutModelB\n\n\x08\x64ut_type\"4\n\x08\x44utModel\x12\x14\n\x0c\x62uild_target\x18\x01 \x01(\t\x12\x12\n\nmodel_name\x18\x02 \x01(\t\"\x8f\x01\n\x0b\x44utTopology\x12\x33\n\x02id\x18\x03 \x01(\x0b\x32\'.chromiumos.test.lab.api.DutTopology.Id\x12*\n\x04\x64uts\x18\x04 \x03(\x0b\x32\x1c.chromiumos.test.lab.api.Dut\x1a\x13\n\x02Id\x12\r\n\x05value\x18\x01 \x01(\tJ\x04\x08\x01\x10\x02J\x04\x08\x02\x10\x03\")\n\x05\x41udio\x12\x11\n\taudio_box\x18\x01 \x01(\x08\x12\r\n\x05\x61trus\x18\x02 \x01(\x08\"\x95\x01\n\x05\x43\x61\x62le\x12\x31\n\x04type\x18\x01 \x01(\x0e\x32#.chromiumos.test.lab.api.Cable.Type\"Y\n\x04Type\x12\x14\n\x10TYPE_UNSPECIFIED\x10\x00\x12\r\n\tAUDIOJACK\x10\x01\x12\x0c\n\x08USBAUDIO\x10\x02\x12\x0f\n\x0bUSBPRINTING\x10\x03\x12\r\n\tHDMIAUDIO\x10\x04\"C\n\x0b\x43\x61\x63heServer\x12\x34\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0b\x32#.chromiumos.test.lab.api.IpEndpoint\"}\n\tCamerabox\x12\x39\n\x06\x66\x61\x63ing\x18\x01 \x01(\x0e\x32).chromiumos.test.lab.api.Camerabox.Facing\"5\n\x06\x46\x61\x63ing\x12\x16\n\x12\x46\x41\x43ING_UNSPECIFIED\x10\x00\x12\x08\n\x04\x42\x41\x43K\x10\x01\x12\t\n\x05\x46RONT\x10\x02\"\x92\x01\n\x08\x43\x65llular\x12=\n\toperators\x18\x01 \x03(\x0e\x32*.chromiumos.test.lab.api.Cellular.Operator\"G\n\x08Operator\x12\x18\n\x14OPERATOR_UNSPECIFIED\x10\x00\x12\x07\n\x03\x41TT\x10\x01\x12\x0b\n\x07VERIZON\x10\x02\x12\x0b\n\x07TMOBILE\x10\x03\"\xf2\x01\n\tChameleon\x12\x42\n\x0bperipherals\x18\x01 \x03(\x0e\x32-.chromiumos.test.lab.api.Chameleon.Peripheral\x12\x13\n\x0b\x61udio_board\x18\x02 \x01(\x08\"\x8b\x01\n\nPeripheral\x12\x1a\n\x16PREIPHERAL_UNSPECIFIED\x10\x00\x12\n\n\x06\x42T_HID\x10\x01\x12\x06\n\x02\x44P\x10\x02\x12\x0b\n\x07\x44P_HDMI\x10\x03\x12\x07\n\x03VGA\x10\x04\x12\x08\n\x04HDMI\x10\x05\x12\x0e\n\nBT_BLE_HID\x10\x06\x12\x10\n\x0c\x42T_A2DP_SINK\x10\x07\x12\x0b\n\x07\x42T_PEER\x10\x08\"\x83\x01\n\x0e\x45xternalCamera\x12:\n\x04type\x18\x01 \x01(\x0e\x32,.chromiumos.test.lab.api.ExternalCamera.Type\"5\n\x04Type\x12\x14\n\x10TYPE_UNSPECIFIED\x10\x00\x12\n\n\x06HUDDLY\x10\x01\x12\x0b\n\x07PTZPRO2\x10\x02\"\x16\n\x03RPM\x12\x0f\n\x07present\x18\x01 \x01(\x08\"U\n\x05Servo\x12\x0f\n\x07present\x18\x01 \x01(\x08\x12;\n\x0eservod_address\x18\x02 \x01(\x0b\x32#.chromiumos.test.lab.api.IpEndpoint\"\x15\n\x05Touch\x12\x0c\n\x04mimo\x18\x01 \x01(\x08\"\xe6\x01\n\x04Wifi\x12>\n\x0b\x65nvironment\x18\x01 \x01(\x0e\x32).chromiumos.test.lab.api.Wifi.Environment\x12\x35\n\x07\x61ntenna\x18\x02 \x01(\x0b\x32$.chromiumos.test.lab.api.WifiAntenna\"g\n\x0b\x45nvironment\x12\x1b\n\x17\x45NVIRONMENT_UNSPECIFIED\x10\x00\x12\x0c\n\x08STANDARD\x10\x01\x12\r\n\tWIFI_CELL\x10\x02\x12\t\n\x05\x43HAOS\x10\x03\x12\x13\n\x0fROUTER_802_11AX\x10\x04\"\x95\x01\n\x0bWifiAntenna\x12\x43\n\nconnection\x18\x01 \x01(\x0e\x32/.chromiumos.test.lab.api.WifiAntenna.Connection\"A\n\nConnection\x12\x1a\n\x16\x43ONNECTION_UNSPECIFIED\x10\x00\x12\x0e\n\nCONDUCTIVE\x10\x01\x12\x07\n\x03OTA\x10\x02\x42\x33Z1go.chromium.org/chromiumos/config/go/test/lab/apib\x06proto3'
   ,
   dependencies=[chromiumos_dot_config_dot_api_dot_device__config__id__pb2.DESCRIPTOR,chromiumos_dot_test_dot_lab_dot_api_dot_ip__endpoint__pb2.DESCRIPTOR,])
 
@@ -55,8 +55,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1315,
-  serialized_end=1404,
+  serialized_start=1581,
+  serialized_end=1670,
 )
 _sym_db.RegisterEnumDescriptor(_CABLE_TYPE)
 
@@ -81,8 +81,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1547,
-  serialized_end=1600,
+  serialized_start=1813,
+  serialized_end=1866,
 )
 _sym_db.RegisterEnumDescriptor(_CAMERABOX_FACING)
 
@@ -111,8 +111,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1678,
-  serialized_end=1749,
+  serialized_start=1944,
+  serialized_end=2015,
 )
 _sym_db.RegisterEnumDescriptor(_CELLULAR_OPERATOR)
 
@@ -161,8 +161,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1855,
-  serialized_end=1994,
+  serialized_start=2121,
+  serialized_end=2260,
 )
 _sym_db.RegisterEnumDescriptor(_CHAMELEON_PERIPHERAL)
 
@@ -187,8 +187,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2075,
-  serialized_end=2128,
+  serialized_start=2341,
+  serialized_end=2394,
 )
 _sym_db.RegisterEnumDescriptor(_EXTERNALCAMERA_TYPE)
 
@@ -221,8 +221,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2392,
-  serialized_end=2495,
+  serialized_start=2658,
+  serialized_end=2761,
 )
 _sym_db.RegisterEnumDescriptor(_WIFI_ENVIRONMENT)
 
@@ -247,8 +247,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2582,
-  serialized_end=2647,
+  serialized_start=2848,
+  serialized_end=2913,
 )
 _sym_db.RegisterEnumDescriptor(_WIFIANTENNA_CONNECTION)
 
@@ -305,70 +305,77 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='servo', full_name='chromiumos.test.lab.api.Dut.ChromeOS.servo', index=2,
+      name='dut_model', full_name='chromiumos.test.lab.api.Dut.ChromeOS.dut_model', index=2,
+      number=14, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='servo', full_name='chromiumos.test.lab.api.Dut.ChromeOS.servo', index=3,
       number=4, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='chameleon', full_name='chromiumos.test.lab.api.Dut.ChromeOS.chameleon', index=3,
+      name='chameleon', full_name='chromiumos.test.lab.api.Dut.ChromeOS.chameleon', index=4,
       number=5, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='rpm', full_name='chromiumos.test.lab.api.Dut.ChromeOS.rpm', index=4,
+      name='rpm', full_name='chromiumos.test.lab.api.Dut.ChromeOS.rpm', index=5,
       number=6, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='external_cameras', full_name='chromiumos.test.lab.api.Dut.ChromeOS.external_cameras', index=5,
+      name='external_cameras', full_name='chromiumos.test.lab.api.Dut.ChromeOS.external_cameras', index=6,
       number=7, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='audio', full_name='chromiumos.test.lab.api.Dut.ChromeOS.audio', index=6,
+      name='audio', full_name='chromiumos.test.lab.api.Dut.ChromeOS.audio', index=7,
       number=8, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='wifi', full_name='chromiumos.test.lab.api.Dut.ChromeOS.wifi', index=7,
+      name='wifi', full_name='chromiumos.test.lab.api.Dut.ChromeOS.wifi', index=8,
       number=9, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='touch', full_name='chromiumos.test.lab.api.Dut.ChromeOS.touch', index=8,
+      name='touch', full_name='chromiumos.test.lab.api.Dut.ChromeOS.touch', index=9,
       number=10, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='camerabox', full_name='chromiumos.test.lab.api.Dut.ChromeOS.camerabox', index=9,
+      name='camerabox', full_name='chromiumos.test.lab.api.Dut.ChromeOS.camerabox', index=10,
       number=11, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='cables', full_name='chromiumos.test.lab.api.Dut.ChromeOS.cables', index=10,
+      name='cables', full_name='chromiumos.test.lab.api.Dut.ChromeOS.cables', index=11,
       number=12, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='cellular', full_name='chromiumos.test.lab.api.Dut.ChromeOS.cellular', index=11,
+      name='cellular', full_name='chromiumos.test.lab.api.Dut.ChromeOS.cellular', index=12,
       number=13, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
@@ -387,7 +394,7 @@
   oneofs=[
   ],
   serialized_start=402,
-  serialized_end=1040,
+  serialized_end=1094,
 )
 
 _DUT_ANDROID = _descriptor.Descriptor(
@@ -397,6 +404,34 @@
   file=DESCRIPTOR,
   containing_type=None,
   fields=[
+    _descriptor.FieldDescriptor(
+      name='associated_hostname', full_name='chromiumos.test.lab.api.Dut.Android.associated_hostname', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='name', full_name='chromiumos.test.lab.api.Dut.Android.name', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='serial_number', full_name='chromiumos.test.lab.api.Dut.Android.serial_number', index=2,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='dut_model', full_name='chromiumos.test.lab.api.Dut.Android.dut_model', index=3,
+      number=4, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -409,8 +444,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1042,
-  serialized_end=1051,
+  serialized_start=1097,
+  serialized_end=1263,
 )
 
 _DUT = _descriptor.Descriptor(
@@ -443,7 +478,7 @@
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
       name='cache_server', full_name='chromiumos.test.lab.api.Dut.cache_server', index=3,
-      number=14, type=11, cpp_type=10, label=1,
+      number=4, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
@@ -464,7 +499,45 @@
       index=0, containing_type=None, fields=[]),
   ],
   serialized_start=152,
-  serialized_end=1063,
+  serialized_end=1275,
+)
+
+
+_DUTMODEL = _descriptor.Descriptor(
+  name='DutModel',
+  full_name='chromiumos.test.lab.api.DutModel',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='build_target', full_name='chromiumos.test.lab.api.DutModel.build_target', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='model_name', full_name='chromiumos.test.lab.api.DutModel.model_name', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1277,
+  serialized_end=1329,
 )
 
 
@@ -531,8 +604,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1066,
-  serialized_end=1209,
+  serialized_start=1332,
+  serialized_end=1475,
 )
 
 
@@ -569,8 +642,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1211,
-  serialized_end=1252,
+  serialized_start=1477,
+  serialized_end=1518,
 )
 
 
@@ -601,8 +674,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1255,
-  serialized_end=1404,
+  serialized_start=1521,
+  serialized_end=1670,
 )
 
 
@@ -632,8 +705,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1406,
-  serialized_end=1473,
+  serialized_start=1672,
+  serialized_end=1739,
 )
 
 
@@ -664,8 +737,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1475,
-  serialized_end=1600,
+  serialized_start=1741,
+  serialized_end=1866,
 )
 
 
@@ -696,8 +769,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1603,
-  serialized_end=1749,
+  serialized_start=1869,
+  serialized_end=2015,
 )
 
 
@@ -735,8 +808,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1752,
-  serialized_end=1994,
+  serialized_start=2018,
+  serialized_end=2260,
 )
 
 
@@ -767,8 +840,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1997,
-  serialized_end=2128,
+  serialized_start=2263,
+  serialized_end=2394,
 )
 
 
@@ -798,8 +871,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2130,
-  serialized_end=2152,
+  serialized_start=2396,
+  serialized_end=2418,
 )
 
 
@@ -836,8 +909,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2154,
-  serialized_end=2239,
+  serialized_start=2420,
+  serialized_end=2505,
 )
 
 
@@ -867,8 +940,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2241,
-  serialized_end=2262,
+  serialized_start=2507,
+  serialized_end=2528,
 )
 
 
@@ -906,8 +979,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2265,
-  serialized_end=2495,
+  serialized_start=2531,
+  serialized_end=2761,
 )
 
 
@@ -938,13 +1011,14 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2498,
-  serialized_end=2647,
+  serialized_start=2764,
+  serialized_end=2913,
 )
 
 _DUT_ID.containing_type = _DUT
 _DUT_CHROMEOS.fields_by_name['device_config_id'].message_type = chromiumos_dot_config_dot_api_dot_device__config__id__pb2._DEVICECONFIGID
 _DUT_CHROMEOS.fields_by_name['ssh'].message_type = chromiumos_dot_test_dot_lab_dot_api_dot_ip__endpoint__pb2._IPENDPOINT
+_DUT_CHROMEOS.fields_by_name['dut_model'].message_type = _DUTMODEL
 _DUT_CHROMEOS.fields_by_name['servo'].message_type = _SERVO
 _DUT_CHROMEOS.fields_by_name['chameleon'].message_type = _CHAMELEON
 _DUT_CHROMEOS.fields_by_name['rpm'].message_type = _RPM
@@ -956,6 +1030,8 @@
 _DUT_CHROMEOS.fields_by_name['cables'].message_type = _CABLE
 _DUT_CHROMEOS.fields_by_name['cellular'].message_type = _CELLULAR
 _DUT_CHROMEOS.containing_type = _DUT
+_DUT_ANDROID.fields_by_name['associated_hostname'].message_type = chromiumos_dot_test_dot_lab_dot_api_dot_ip__endpoint__pb2._IPENDPOINT
+_DUT_ANDROID.fields_by_name['dut_model'].message_type = _DUTMODEL
 _DUT_ANDROID.containing_type = _DUT
 _DUT.fields_by_name['id'].message_type = _DUT_ID
 _DUT.fields_by_name['chromeos'].message_type = _DUT_CHROMEOS
@@ -988,6 +1064,7 @@
 _WIFIANTENNA.fields_by_name['connection'].enum_type = _WIFIANTENNA_CONNECTION
 _WIFIANTENNA_CONNECTION.containing_type = _WIFIANTENNA
 DESCRIPTOR.message_types_by_name['Dut'] = _DUT
+DESCRIPTOR.message_types_by_name['DutModel'] = _DUTMODEL
 DESCRIPTOR.message_types_by_name['DutTopology'] = _DUTTOPOLOGY
 DESCRIPTOR.message_types_by_name['Audio'] = _AUDIO
 DESCRIPTOR.message_types_by_name['Cable'] = _CABLE
@@ -1034,6 +1111,13 @@
 _sym_db.RegisterMessage(Dut.ChromeOS)
 _sym_db.RegisterMessage(Dut.Android)
 
+DutModel = _reflection.GeneratedProtocolMessageType('DutModel', (_message.Message,), {
+  'DESCRIPTOR' : _DUTMODEL,
+  '__module__' : 'chromiumos.test.lab.api.dut_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.lab.api.DutModel)
+  })
+_sym_db.RegisterMessage(DutModel)
+
 DutTopology = _reflection.GeneratedProtocolMessageType('DutTopology', (_message.Message,), {
 
   'Id' : _reflection.GeneratedProtocolMessageType('Id', (_message.Message,), {
diff --git a/api/gen_sdk/chromiumos/test/lab/api/tape_service_pb2.py b/api/gen_sdk/chromiumos/test/lab/api/tape_service_pb2.py
new file mode 100644
index 0000000..e8f47ea
--- /dev/null
+++ b/api/gen_sdk/chromiumos/test/lab/api/tape_service_pb2.py
@@ -0,0 +1,153 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: chromiumos/test/lab/api/tape_service.proto
+
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='chromiumos/test/lab/api/tape_service.proto',
+  package='chromiumos.test.lab.api',
+  syntax='proto3',
+  serialized_options=b'Z1go.chromium.org/chromiumos/config/go/test/lab/api',
+  serialized_pb=b'\n*chromiumos/test/lab/api/tape_service.proto\x12\x17\x63hromiumos.test.lab.api\"s\n\x0f\x43\x61llTapeRequest\x12\x18\n\x10request_endpoint\x18\x01 \x01(\t\x12\x16\n\x0erequest_method\x18\x02 \x01(\t\x12\x17\n\x0frequest_timeout\x18\x03 \x01(\x05\x12\x15\n\rpayload_bytes\x18\x04 \x01(\x0c\")\n\x10\x43\x61llTapeResponse\x12\x15\n\rpayload_bytes\x18\x01 \x01(\x0c\x32n\n\x0bTapeService\x12_\n\x08\x43\x61llTape\x12(.chromiumos.test.lab.api.CallTapeRequest\x1a).chromiumos.test.lab.api.CallTapeResponseB3Z1go.chromium.org/chromiumos/config/go/test/lab/apib\x06proto3'
+)
+
+
+
+
+_CALLTAPEREQUEST = _descriptor.Descriptor(
+  name='CallTapeRequest',
+  full_name='chromiumos.test.lab.api.CallTapeRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='request_endpoint', full_name='chromiumos.test.lab.api.CallTapeRequest.request_endpoint', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='request_method', full_name='chromiumos.test.lab.api.CallTapeRequest.request_method', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='request_timeout', full_name='chromiumos.test.lab.api.CallTapeRequest.request_timeout', index=2,
+      number=3, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='payload_bytes', full_name='chromiumos.test.lab.api.CallTapeRequest.payload_bytes', index=3,
+      number=4, type=12, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"",
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=71,
+  serialized_end=186,
+)
+
+
+_CALLTAPERESPONSE = _descriptor.Descriptor(
+  name='CallTapeResponse',
+  full_name='chromiumos.test.lab.api.CallTapeResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='payload_bytes', full_name='chromiumos.test.lab.api.CallTapeResponse.payload_bytes', index=0,
+      number=1, type=12, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"",
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=188,
+  serialized_end=229,
+)
+
+DESCRIPTOR.message_types_by_name['CallTapeRequest'] = _CALLTAPEREQUEST
+DESCRIPTOR.message_types_by_name['CallTapeResponse'] = _CALLTAPERESPONSE
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+CallTapeRequest = _reflection.GeneratedProtocolMessageType('CallTapeRequest', (_message.Message,), {
+  'DESCRIPTOR' : _CALLTAPEREQUEST,
+  '__module__' : 'chromiumos.test.lab.api.tape_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.lab.api.CallTapeRequest)
+  })
+_sym_db.RegisterMessage(CallTapeRequest)
+
+CallTapeResponse = _reflection.GeneratedProtocolMessageType('CallTapeResponse', (_message.Message,), {
+  'DESCRIPTOR' : _CALLTAPERESPONSE,
+  '__module__' : 'chromiumos.test.lab.api.tape_service_pb2'
+  # @@protoc_insertion_point(class_scope:chromiumos.test.lab.api.CallTapeResponse)
+  })
+_sym_db.RegisterMessage(CallTapeResponse)
+
+
+DESCRIPTOR._options = None
+
+_TAPESERVICE = _descriptor.ServiceDescriptor(
+  name='TapeService',
+  full_name='chromiumos.test.lab.api.TapeService',
+  file=DESCRIPTOR,
+  index=0,
+  serialized_options=None,
+  serialized_start=231,
+  serialized_end=341,
+  methods=[
+  _descriptor.MethodDescriptor(
+    name='CallTape',
+    full_name='chromiumos.test.lab.api.TapeService.CallTape',
+    index=0,
+    containing_service=None,
+    input_type=_CALLTAPEREQUEST,
+    output_type=_CALLTAPERESPONSE,
+    serialized_options=None,
+  ),
+])
+_sym_db.RegisterServiceDescriptor(_TAPESERVICE)
+
+DESCRIPTOR.services_by_name['TapeService'] = _TAPESERVICE
+
+# @@protoc_insertion_point(module_scope)
diff --git a/api/gen_sdk/chromiumos/test/plan/source_test_plan_pb2.py b/api/gen_sdk/chromiumos/test/plan/source_test_plan_pb2.py
index ea5165b..fd5e602 100644
--- a/api/gen_sdk/chromiumos/test/plan/source_test_plan_pb2.py
+++ b/api/gen_sdk/chromiumos/test/plan/source_test_plan_pb2.py
@@ -18,37 +18,11 @@
   package='chromiumos.test.plan',
   syntax='proto3',
   serialized_options=b'Z.go.chromium.org/chromiumos/config/go/test/plan',
-  serialized_pb=b'\n+chromiumos/test/plan/source_test_plan.proto\x12\x14\x63hromiumos.test.plan\"\x99\x0c\n\x0eSourceTestPlan\x12[\n\x19\x65nabled_test_environments\x18\x01 \x03(\x0e\x32\x34.chromiumos.test.plan.SourceTestPlan.TestEnvironmentB\x02\x18\x01\x12\x14\n\x0cpath_regexps\x18\x02 \x03(\t\x12\x1c\n\x14path_regexp_excludes\x18\x03 \x03(\t\x12[\n\x18test_plan_starlark_files\x18\x0f \x03(\x0b\x32\x39.chromiumos.test.plan.SourceTestPlan.TestPlanStarlarkFile\x12\x15\n\ttest_tags\x18\x04 \x03(\tB\x02\x18\x01\x12\x1d\n\x11test_tag_excludes\x18\x05 \x03(\tB\x02\x18\x01\x12K\n\x0crequirements\x18\r \x01(\x0b\x32\x31.chromiumos.test.plan.SourceTestPlan.RequirementsB\x02\x18\x01\x1a\x32\n\x14TestPlanStarlarkFile\x12\x0c\n\x04repo\x18\x01 \x01(\t\x12\x0c\n\x04path\x18\x02 \x01(\t\x1a\x8b\x08\n\x0cRequirements\x12Y\n\x0fkernel_versions\x18\x01 \x01(\x0b\x32@.chromiumos.test.plan.SourceTestPlan.Requirements.KernelVersions\x12S\n\x0csoc_families\x18\x02 \x01(\x0b\x32=.chromiumos.test.plan.SourceTestPlan.Requirements.SocFamilies\x12V\n\rarchitectures\x18\x03 \x01(\x0b\x32?.chromiumos.test.plan.SourceTestPlan.Requirements.Architectures\x12S\n\x0c\x61rc_versions\x18\x04 \x01(\x0b\x32=.chromiumos.test.plan.SourceTestPlan.Requirements.ArcVersions\x12R\n\x0b\x66ingerprint\x18\x05 \x01(\x0b\x32=.chromiumos.test.plan.SourceTestPlan.Requirements.Fingerprint\x12N\n\tparallels\x18\x06 \x01(\x0b\x32;.chromiumos.test.plan.SourceTestPlan.Requirements.Parallels\x12Y\n\x0f\x63hromeos_config\x18\x07 \x01(\x0b\x32@.chromiumos.test.plan.SourceTestPlan.Requirements.ChromeOSConfig\x12\x62\n\x14\x66irmware_ro_versions\x18\x08 \x01(\x0b\x32\x44.chromiumos.test.plan.SourceTestPlan.Requirements.FirmwareROVersions\x1a\x10\n\x0eKernelVersions\x1a\r\n\x0bSocFamilies\x1a\x0f\n\rArchitectures\x1a\r\n\x0b\x41rcVersions\x1a\r\n\x0b\x46ingerprint\x1a\x0b\n\tParallels\x1a\x10\n\x0e\x43hromeOSConfig\x1a\xcb\x01\n\x12\x46irmwareROVersions\x12z\n\x14program_to_milestone\x18\x01 \x03(\x0b\x32\\.chromiumos.test.plan.SourceTestPlan.Requirements.FirmwareROVersions.ProgramToMilestoneEntry\x1a\x39\n\x17ProgramToMilestoneEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\"N\n\x0fTestEnvironment\x12 \n\x1cTEST_ENVIRONMENT_UNSPECIFIED\x10\x00\x12\x0c\n\x08HARDWARE\x10\x01\x12\x0b\n\x07VIRTUAL\x10\x02J\x04\x08\x06\x10\rB0Z.go.chromium.org/chromiumos/config/go/test/planb\x06proto3'
+  serialized_pb=b'\n+chromiumos/test/plan/source_test_plan.proto\x12\x14\x63hromiumos.test.plan\"\xf2\x01\n\x0eSourceTestPlan\x12\x14\n\x0cpath_regexps\x18\x02 \x03(\t\x12\x1c\n\x14path_regexp_excludes\x18\x03 \x03(\t\x12[\n\x18test_plan_starlark_files\x18\x0f \x03(\x0b\x32\x39.chromiumos.test.plan.SourceTestPlan.TestPlanStarlarkFile\x1a\x43\n\x14TestPlanStarlarkFile\x12\x0c\n\x04host\x18\x01 \x01(\t\x12\x0f\n\x07project\x18\x02 \x01(\t\x12\x0c\n\x04path\x18\x03 \x01(\tJ\x04\x08\x01\x10\x02J\x04\x08\x04\x10\x0f\x42\x30Z.go.chromium.org/chromiumos/config/go/test/planb\x06proto3'
 )
 
 
 
-_SOURCETESTPLAN_TESTENVIRONMENT = _descriptor.EnumDescriptor(
-  name='TestEnvironment',
-  full_name='chromiumos.test.plan.SourceTestPlan.TestEnvironment',
-  filename=None,
-  file=DESCRIPTOR,
-  values=[
-    _descriptor.EnumValueDescriptor(
-      name='TEST_ENVIRONMENT_UNSPECIFIED', index=0, number=0,
-      serialized_options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='HARDWARE', index=1, number=1,
-      serialized_options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='VIRTUAL', index=2, number=2,
-      serialized_options=None,
-      type=None),
-  ],
-  containing_type=None,
-  serialized_options=None,
-  serialized_start=1547,
-  serialized_end=1625,
-)
-_sym_db.RegisterEnumDescriptor(_SOURCETESTPLAN_TESTENVIRONMENT)
-
 
 _SOURCETESTPLAN_TESTPLANSTARLARKFILE = _descriptor.Descriptor(
   name='TestPlanStarlarkFile',
@@ -58,340 +32,40 @@
   containing_type=None,
   fields=[
     _descriptor.FieldDescriptor(
-      name='repo', full_name='chromiumos.test.plan.SourceTestPlan.TestPlanStarlarkFile.repo', index=0,
+      name='host', full_name='chromiumos.test.plan.SourceTestPlan.TestPlanStarlarkFile.host', index=0,
       number=1, type=9, cpp_type=9, label=1,
       has_default_value=False, default_value=b"".decode('utf-8'),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='path', full_name='chromiumos.test.plan.SourceTestPlan.TestPlanStarlarkFile.path', index=1,
+      name='project', full_name='chromiumos.test.plan.SourceTestPlan.TestPlanStarlarkFile.project', index=1,
       number=2, type=9, cpp_type=9, label=1,
       has_default_value=False, default_value=b"".decode('utf-8'),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=457,
-  serialized_end=507,
-)
-
-_SOURCETESTPLAN_REQUIREMENTS_KERNELVERSIONS = _descriptor.Descriptor(
-  name='KernelVersions',
-  full_name='chromiumos.test.plan.SourceTestPlan.Requirements.KernelVersions',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1230,
-  serialized_end=1246,
-)
-
-_SOURCETESTPLAN_REQUIREMENTS_SOCFAMILIES = _descriptor.Descriptor(
-  name='SocFamilies',
-  full_name='chromiumos.test.plan.SourceTestPlan.Requirements.SocFamilies',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1248,
-  serialized_end=1261,
-)
-
-_SOURCETESTPLAN_REQUIREMENTS_ARCHITECTURES = _descriptor.Descriptor(
-  name='Architectures',
-  full_name='chromiumos.test.plan.SourceTestPlan.Requirements.Architectures',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1263,
-  serialized_end=1278,
-)
-
-_SOURCETESTPLAN_REQUIREMENTS_ARCVERSIONS = _descriptor.Descriptor(
-  name='ArcVersions',
-  full_name='chromiumos.test.plan.SourceTestPlan.Requirements.ArcVersions',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1280,
-  serialized_end=1293,
-)
-
-_SOURCETESTPLAN_REQUIREMENTS_FINGERPRINT = _descriptor.Descriptor(
-  name='Fingerprint',
-  full_name='chromiumos.test.plan.SourceTestPlan.Requirements.Fingerprint',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1295,
-  serialized_end=1308,
-)
-
-_SOURCETESTPLAN_REQUIREMENTS_PARALLELS = _descriptor.Descriptor(
-  name='Parallels',
-  full_name='chromiumos.test.plan.SourceTestPlan.Requirements.Parallels',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1310,
-  serialized_end=1321,
-)
-
-_SOURCETESTPLAN_REQUIREMENTS_CHROMEOSCONFIG = _descriptor.Descriptor(
-  name='ChromeOSConfig',
-  full_name='chromiumos.test.plan.SourceTestPlan.Requirements.ChromeOSConfig',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1323,
-  serialized_end=1339,
-)
-
-_SOURCETESTPLAN_REQUIREMENTS_FIRMWAREROVERSIONS_PROGRAMTOMILESTONEENTRY = _descriptor.Descriptor(
-  name='ProgramToMilestoneEntry',
-  full_name='chromiumos.test.plan.SourceTestPlan.Requirements.FirmwareROVersions.ProgramToMilestoneEntry',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
     _descriptor.FieldDescriptor(
-      name='key', full_name='chromiumos.test.plan.SourceTestPlan.Requirements.FirmwareROVersions.ProgramToMilestoneEntry.key', index=0,
-      number=1, type=9, cpp_type=9, label=1,
+      name='path', full_name='chromiumos.test.plan.SourceTestPlan.TestPlanStarlarkFile.path', index=2,
+      number=3, type=9, cpp_type=9, label=1,
       has_default_value=False, default_value=b"".decode('utf-8'),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='value', full_name='chromiumos.test.plan.SourceTestPlan.Requirements.FirmwareROVersions.ProgramToMilestoneEntry.value', index=1,
-      number=2, type=5, cpp_type=1, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
   nested_types=[],
   enum_types=[
   ],
-  serialized_options=b'8\001',
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1488,
-  serialized_end=1545,
-)
-
-_SOURCETESTPLAN_REQUIREMENTS_FIRMWAREROVERSIONS = _descriptor.Descriptor(
-  name='FirmwareROVersions',
-  full_name='chromiumos.test.plan.SourceTestPlan.Requirements.FirmwareROVersions',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='program_to_milestone', full_name='chromiumos.test.plan.SourceTestPlan.Requirements.FirmwareROVersions.program_to_milestone', index=0,
-      number=1, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-  ],
-  extensions=[
-  ],
-  nested_types=[_SOURCETESTPLAN_REQUIREMENTS_FIRMWAREROVERSIONS_PROGRAMTOMILESTONEENTRY, ],
-  enum_types=[
-  ],
   serialized_options=None,
   is_extendable=False,
   syntax='proto3',
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1342,
-  serialized_end=1545,
-)
-
-_SOURCETESTPLAN_REQUIREMENTS = _descriptor.Descriptor(
-  name='Requirements',
-  full_name='chromiumos.test.plan.SourceTestPlan.Requirements',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='kernel_versions', full_name='chromiumos.test.plan.SourceTestPlan.Requirements.kernel_versions', index=0,
-      number=1, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='soc_families', full_name='chromiumos.test.plan.SourceTestPlan.Requirements.soc_families', index=1,
-      number=2, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='architectures', full_name='chromiumos.test.plan.SourceTestPlan.Requirements.architectures', index=2,
-      number=3, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='arc_versions', full_name='chromiumos.test.plan.SourceTestPlan.Requirements.arc_versions', index=3,
-      number=4, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='fingerprint', full_name='chromiumos.test.plan.SourceTestPlan.Requirements.fingerprint', index=4,
-      number=5, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='parallels', full_name='chromiumos.test.plan.SourceTestPlan.Requirements.parallels', index=5,
-      number=6, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='chromeos_config', full_name='chromiumos.test.plan.SourceTestPlan.Requirements.chromeos_config', index=6,
-      number=7, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='firmware_ro_versions', full_name='chromiumos.test.plan.SourceTestPlan.Requirements.firmware_ro_versions', index=7,
-      number=8, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-  ],
-  extensions=[
-  ],
-  nested_types=[_SOURCETESTPLAN_REQUIREMENTS_KERNELVERSIONS, _SOURCETESTPLAN_REQUIREMENTS_SOCFAMILIES, _SOURCETESTPLAN_REQUIREMENTS_ARCHITECTURES, _SOURCETESTPLAN_REQUIREMENTS_ARCVERSIONS, _SOURCETESTPLAN_REQUIREMENTS_FINGERPRINT, _SOURCETESTPLAN_REQUIREMENTS_PARALLELS, _SOURCETESTPLAN_REQUIREMENTS_CHROMEOSCONFIG, _SOURCETESTPLAN_REQUIREMENTS_FIRMWAREROVERSIONS, ],
-  enum_types=[
-  ],
-  serialized_options=None,
-  is_extendable=False,
-  syntax='proto3',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=510,
-  serialized_end=1545,
+  serialized_start=233,
+  serialized_end=300,
 )
 
 _SOURCETESTPLAN = _descriptor.Descriptor(
@@ -402,60 +76,31 @@
   containing_type=None,
   fields=[
     _descriptor.FieldDescriptor(
-      name='enabled_test_environments', full_name='chromiumos.test.plan.SourceTestPlan.enabled_test_environments', index=0,
-      number=1, type=14, cpp_type=8, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=b'\030\001', file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='path_regexps', full_name='chromiumos.test.plan.SourceTestPlan.path_regexps', index=1,
+      name='path_regexps', full_name='chromiumos.test.plan.SourceTestPlan.path_regexps', index=0,
       number=2, type=9, cpp_type=9, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='path_regexp_excludes', full_name='chromiumos.test.plan.SourceTestPlan.path_regexp_excludes', index=2,
+      name='path_regexp_excludes', full_name='chromiumos.test.plan.SourceTestPlan.path_regexp_excludes', index=1,
       number=3, type=9, cpp_type=9, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='test_plan_starlark_files', full_name='chromiumos.test.plan.SourceTestPlan.test_plan_starlark_files', index=3,
+      name='test_plan_starlark_files', full_name='chromiumos.test.plan.SourceTestPlan.test_plan_starlark_files', index=2,
       number=15, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='test_tags', full_name='chromiumos.test.plan.SourceTestPlan.test_tags', index=4,
-      number=4, type=9, cpp_type=9, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=b'\030\001', file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='test_tag_excludes', full_name='chromiumos.test.plan.SourceTestPlan.test_tag_excludes', index=5,
-      number=5, type=9, cpp_type=9, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=b'\030\001', file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='requirements', full_name='chromiumos.test.plan.SourceTestPlan.requirements', index=6,
-      number=13, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=b'\030\001', file=DESCRIPTOR),
   ],
   extensions=[
   ],
-  nested_types=[_SOURCETESTPLAN_TESTPLANSTARLARKFILE, _SOURCETESTPLAN_REQUIREMENTS, ],
+  nested_types=[_SOURCETESTPLAN_TESTPLANSTARLARKFILE, ],
   enum_types=[
-    _SOURCETESTPLAN_TESTENVIRONMENT,
   ],
   serialized_options=None,
   is_extendable=False,
@@ -464,33 +109,11 @@
   oneofs=[
   ],
   serialized_start=70,
-  serialized_end=1631,
+  serialized_end=312,
 )
 
 _SOURCETESTPLAN_TESTPLANSTARLARKFILE.containing_type = _SOURCETESTPLAN
-_SOURCETESTPLAN_REQUIREMENTS_KERNELVERSIONS.containing_type = _SOURCETESTPLAN_REQUIREMENTS
-_SOURCETESTPLAN_REQUIREMENTS_SOCFAMILIES.containing_type = _SOURCETESTPLAN_REQUIREMENTS
-_SOURCETESTPLAN_REQUIREMENTS_ARCHITECTURES.containing_type = _SOURCETESTPLAN_REQUIREMENTS
-_SOURCETESTPLAN_REQUIREMENTS_ARCVERSIONS.containing_type = _SOURCETESTPLAN_REQUIREMENTS
-_SOURCETESTPLAN_REQUIREMENTS_FINGERPRINT.containing_type = _SOURCETESTPLAN_REQUIREMENTS
-_SOURCETESTPLAN_REQUIREMENTS_PARALLELS.containing_type = _SOURCETESTPLAN_REQUIREMENTS
-_SOURCETESTPLAN_REQUIREMENTS_CHROMEOSCONFIG.containing_type = _SOURCETESTPLAN_REQUIREMENTS
-_SOURCETESTPLAN_REQUIREMENTS_FIRMWAREROVERSIONS_PROGRAMTOMILESTONEENTRY.containing_type = _SOURCETESTPLAN_REQUIREMENTS_FIRMWAREROVERSIONS
-_SOURCETESTPLAN_REQUIREMENTS_FIRMWAREROVERSIONS.fields_by_name['program_to_milestone'].message_type = _SOURCETESTPLAN_REQUIREMENTS_FIRMWAREROVERSIONS_PROGRAMTOMILESTONEENTRY
-_SOURCETESTPLAN_REQUIREMENTS_FIRMWAREROVERSIONS.containing_type = _SOURCETESTPLAN_REQUIREMENTS
-_SOURCETESTPLAN_REQUIREMENTS.fields_by_name['kernel_versions'].message_type = _SOURCETESTPLAN_REQUIREMENTS_KERNELVERSIONS
-_SOURCETESTPLAN_REQUIREMENTS.fields_by_name['soc_families'].message_type = _SOURCETESTPLAN_REQUIREMENTS_SOCFAMILIES
-_SOURCETESTPLAN_REQUIREMENTS.fields_by_name['architectures'].message_type = _SOURCETESTPLAN_REQUIREMENTS_ARCHITECTURES
-_SOURCETESTPLAN_REQUIREMENTS.fields_by_name['arc_versions'].message_type = _SOURCETESTPLAN_REQUIREMENTS_ARCVERSIONS
-_SOURCETESTPLAN_REQUIREMENTS.fields_by_name['fingerprint'].message_type = _SOURCETESTPLAN_REQUIREMENTS_FINGERPRINT
-_SOURCETESTPLAN_REQUIREMENTS.fields_by_name['parallels'].message_type = _SOURCETESTPLAN_REQUIREMENTS_PARALLELS
-_SOURCETESTPLAN_REQUIREMENTS.fields_by_name['chromeos_config'].message_type = _SOURCETESTPLAN_REQUIREMENTS_CHROMEOSCONFIG
-_SOURCETESTPLAN_REQUIREMENTS.fields_by_name['firmware_ro_versions'].message_type = _SOURCETESTPLAN_REQUIREMENTS_FIRMWAREROVERSIONS
-_SOURCETESTPLAN_REQUIREMENTS.containing_type = _SOURCETESTPLAN
-_SOURCETESTPLAN.fields_by_name['enabled_test_environments'].enum_type = _SOURCETESTPLAN_TESTENVIRONMENT
 _SOURCETESTPLAN.fields_by_name['test_plan_starlark_files'].message_type = _SOURCETESTPLAN_TESTPLANSTARLARKFILE
-_SOURCETESTPLAN.fields_by_name['requirements'].message_type = _SOURCETESTPLAN_REQUIREMENTS
-_SOURCETESTPLAN_TESTENVIRONMENT.containing_type = _SOURCETESTPLAN
 DESCRIPTOR.message_types_by_name['SourceTestPlan'] = _SOURCETESTPLAN
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
@@ -502,98 +125,13 @@
     # @@protoc_insertion_point(class_scope:chromiumos.test.plan.SourceTestPlan.TestPlanStarlarkFile)
     })
   ,
-
-  'Requirements' : _reflection.GeneratedProtocolMessageType('Requirements', (_message.Message,), {
-
-    'KernelVersions' : _reflection.GeneratedProtocolMessageType('KernelVersions', (_message.Message,), {
-      'DESCRIPTOR' : _SOURCETESTPLAN_REQUIREMENTS_KERNELVERSIONS,
-      '__module__' : 'chromiumos.test.plan.source_test_plan_pb2'
-      # @@protoc_insertion_point(class_scope:chromiumos.test.plan.SourceTestPlan.Requirements.KernelVersions)
-      })
-    ,
-
-    'SocFamilies' : _reflection.GeneratedProtocolMessageType('SocFamilies', (_message.Message,), {
-      'DESCRIPTOR' : _SOURCETESTPLAN_REQUIREMENTS_SOCFAMILIES,
-      '__module__' : 'chromiumos.test.plan.source_test_plan_pb2'
-      # @@protoc_insertion_point(class_scope:chromiumos.test.plan.SourceTestPlan.Requirements.SocFamilies)
-      })
-    ,
-
-    'Architectures' : _reflection.GeneratedProtocolMessageType('Architectures', (_message.Message,), {
-      'DESCRIPTOR' : _SOURCETESTPLAN_REQUIREMENTS_ARCHITECTURES,
-      '__module__' : 'chromiumos.test.plan.source_test_plan_pb2'
-      # @@protoc_insertion_point(class_scope:chromiumos.test.plan.SourceTestPlan.Requirements.Architectures)
-      })
-    ,
-
-    'ArcVersions' : _reflection.GeneratedProtocolMessageType('ArcVersions', (_message.Message,), {
-      'DESCRIPTOR' : _SOURCETESTPLAN_REQUIREMENTS_ARCVERSIONS,
-      '__module__' : 'chromiumos.test.plan.source_test_plan_pb2'
-      # @@protoc_insertion_point(class_scope:chromiumos.test.plan.SourceTestPlan.Requirements.ArcVersions)
-      })
-    ,
-
-    'Fingerprint' : _reflection.GeneratedProtocolMessageType('Fingerprint', (_message.Message,), {
-      'DESCRIPTOR' : _SOURCETESTPLAN_REQUIREMENTS_FINGERPRINT,
-      '__module__' : 'chromiumos.test.plan.source_test_plan_pb2'
-      # @@protoc_insertion_point(class_scope:chromiumos.test.plan.SourceTestPlan.Requirements.Fingerprint)
-      })
-    ,
-
-    'Parallels' : _reflection.GeneratedProtocolMessageType('Parallels', (_message.Message,), {
-      'DESCRIPTOR' : _SOURCETESTPLAN_REQUIREMENTS_PARALLELS,
-      '__module__' : 'chromiumos.test.plan.source_test_plan_pb2'
-      # @@protoc_insertion_point(class_scope:chromiumos.test.plan.SourceTestPlan.Requirements.Parallels)
-      })
-    ,
-
-    'ChromeOSConfig' : _reflection.GeneratedProtocolMessageType('ChromeOSConfig', (_message.Message,), {
-      'DESCRIPTOR' : _SOURCETESTPLAN_REQUIREMENTS_CHROMEOSCONFIG,
-      '__module__' : 'chromiumos.test.plan.source_test_plan_pb2'
-      # @@protoc_insertion_point(class_scope:chromiumos.test.plan.SourceTestPlan.Requirements.ChromeOSConfig)
-      })
-    ,
-
-    'FirmwareROVersions' : _reflection.GeneratedProtocolMessageType('FirmwareROVersions', (_message.Message,), {
-
-      'ProgramToMilestoneEntry' : _reflection.GeneratedProtocolMessageType('ProgramToMilestoneEntry', (_message.Message,), {
-        'DESCRIPTOR' : _SOURCETESTPLAN_REQUIREMENTS_FIRMWAREROVERSIONS_PROGRAMTOMILESTONEENTRY,
-        '__module__' : 'chromiumos.test.plan.source_test_plan_pb2'
-        # @@protoc_insertion_point(class_scope:chromiumos.test.plan.SourceTestPlan.Requirements.FirmwareROVersions.ProgramToMilestoneEntry)
-        })
-      ,
-      'DESCRIPTOR' : _SOURCETESTPLAN_REQUIREMENTS_FIRMWAREROVERSIONS,
-      '__module__' : 'chromiumos.test.plan.source_test_plan_pb2'
-      # @@protoc_insertion_point(class_scope:chromiumos.test.plan.SourceTestPlan.Requirements.FirmwareROVersions)
-      })
-    ,
-    'DESCRIPTOR' : _SOURCETESTPLAN_REQUIREMENTS,
-    '__module__' : 'chromiumos.test.plan.source_test_plan_pb2'
-    # @@protoc_insertion_point(class_scope:chromiumos.test.plan.SourceTestPlan.Requirements)
-    })
-  ,
   'DESCRIPTOR' : _SOURCETESTPLAN,
   '__module__' : 'chromiumos.test.plan.source_test_plan_pb2'
   # @@protoc_insertion_point(class_scope:chromiumos.test.plan.SourceTestPlan)
   })
 _sym_db.RegisterMessage(SourceTestPlan)
 _sym_db.RegisterMessage(SourceTestPlan.TestPlanStarlarkFile)
-_sym_db.RegisterMessage(SourceTestPlan.Requirements)
-_sym_db.RegisterMessage(SourceTestPlan.Requirements.KernelVersions)
-_sym_db.RegisterMessage(SourceTestPlan.Requirements.SocFamilies)
-_sym_db.RegisterMessage(SourceTestPlan.Requirements.Architectures)
-_sym_db.RegisterMessage(SourceTestPlan.Requirements.ArcVersions)
-_sym_db.RegisterMessage(SourceTestPlan.Requirements.Fingerprint)
-_sym_db.RegisterMessage(SourceTestPlan.Requirements.Parallels)
-_sym_db.RegisterMessage(SourceTestPlan.Requirements.ChromeOSConfig)
-_sym_db.RegisterMessage(SourceTestPlan.Requirements.FirmwareROVersions)
-_sym_db.RegisterMessage(SourceTestPlan.Requirements.FirmwareROVersions.ProgramToMilestoneEntry)
 
 
 DESCRIPTOR._options = None
-_SOURCETESTPLAN_REQUIREMENTS_FIRMWAREROVERSIONS_PROGRAMTOMILESTONEENTRY._options = None
-_SOURCETESTPLAN.fields_by_name['enabled_test_environments']._options = None
-_SOURCETESTPLAN.fields_by_name['test_tags']._options = None
-_SOURCETESTPLAN.fields_by_name['test_tag_excludes']._options = None
-_SOURCETESTPLAN.fields_by_name['requirements']._options = None
 # @@protoc_insertion_point(module_scope)
diff --git a/api/gen_sdk/test_platform/execution/param_pb2.py b/api/gen_sdk/test_platform/execution/param_pb2.py
index 15e5eb6..23f27d9 100644
--- a/api/gen_sdk/test_platform/execution/param_pb2.py
+++ b/api/gen_sdk/test_platform/execution/param_pb2.py
@@ -11,6 +11,7 @@
 _sym_db = _symbol_database.Default()
 
 
+from chromite.api.gen_sdk.chromiumos.build.api import container_metadata_pb2 as chromiumos_dot_build_dot_api_dot_container__metadata__pb2
 
 
 DESCRIPTOR = _descriptor.FileDescriptor(
@@ -18,8 +19,9 @@
   package='test_platform.execution',
   syntax='proto3',
   serialized_options=b'ZAgo.chromium.org/chromiumos/infra/proto/go/test_platform/execution',
-  serialized_pb=b'\n#test_platform/execution/param.proto\x12\x17test_platform.execution\"\x1f\n\x05Param\x12\x16\n\x0eupload_crashes\x18\x01 \x01(\x08\x42\x43ZAgo.chromium.org/chromiumos/infra/proto/go/test_platform/executionb\x06proto3'
-)
+  serialized_pb=b'\n#test_platform/execution/param.proto\x12\x17test_platform.execution\x1a-chromiumos/build/api/container_metadata.proto\"g\n\x05Param\x12\x16\n\x0eupload_crashes\x18\x01 \x01(\x08\x12\x46\n\x14\x63ontainer_image_info\x18\x08 \x01(\x0b\x32(.chromiumos.build.api.ContainerImageInfoBCZAgo.chromium.org/chromiumos/infra/proto/go/test_platform/executionb\x06proto3'
+  ,
+  dependencies=[chromiumos_dot_build_dot_api_dot_container__metadata__pb2.DESCRIPTOR,])
 
 
 
@@ -38,6 +40,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='container_image_info', full_name='test_platform.execution.Param.container_image_info', index=1,
+      number=8, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -50,10 +59,11 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=64,
-  serialized_end=95,
+  serialized_start=111,
+  serialized_end=214,
 )
 
+_PARAM.fields_by_name['container_image_info'].message_type = chromiumos_dot_build_dot_api_dot_container__metadata__pb2._CONTAINERIMAGEINFO
 DESCRIPTOR.message_types_by_name['Param'] = _PARAM
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
diff --git a/api/gen_sdk/test_platform/phosphorus/common_pb2.py b/api/gen_sdk/test_platform/phosphorus/common_pb2.py
index 6dcb411..44b7f9d 100644
--- a/api/gen_sdk/test_platform/phosphorus/common_pb2.py
+++ b/api/gen_sdk/test_platform/phosphorus/common_pb2.py
@@ -18,7 +18,7 @@
   package='test_platform.phosphorus',
   syntax='proto3',
   serialized_options=b'ZBgo.chromium.org/chromiumos/infra/proto/go/test_platform/phosphorus',
-  serialized_pb=b'\n%test_platform/phosphorus/common.proto\x12\x18test_platform.phosphorus\"&\n\x0e\x42otEnvironment\x12\x14\n\x0c\x61utotest_dir\x18\x01 \x01(\t\"|\n\x0fTaskEnvironment\x12\x13\n\x0bresults_dir\x18\x02 \x01(\t\x12\x18\n\x10test_results_dir\x18\x03 \x01(\t\x12\x1b\n\x13ssp_base_image_name\x18\x04 \x01(\tJ\x04\x08\x01\x10\x02R\x17synchronous_offload_dir\"`\n\nPrejobStep\x12R\n\x18provision_dut_experiment\x18\x01 \x01(\x0b\x32\x30.test_platform.phosphorus.ProvisionDutExperiment\"\xc0\x02\n\x16ProvisionDutExperiment\x12\x0f\n\x07\x65nabled\x18\x01 \x01(\x08\x12g\n\x17\x63ros_version_allow_list\x18\x02 \x01(\x0b\x32\x44.test_platform.phosphorus.ProvisionDutExperiment.CrosVersionSelectorH\x00\x12j\n\x1a\x63ros_version_disallow_list\x18\x03 \x01(\x0b\x32\x44.test_platform.phosphorus.ProvisionDutExperiment.CrosVersionSelectorH\x00\x1a\'\n\x13\x43rosVersionSelector\x12\x10\n\x08prefixes\x18\x01 \x03(\tB\x17\n\x15\x63ros_version_selector\"3\n\x11LogDataUploadStep\x12\x1e\n\x16max_concurrent_uploads\x18\x01 \x01(\x05\"R\n\x10\x46\x65tchCrashesStep\x12\x1f\n\x17\x63rash_server_report_url\x18\x01 \x01(\t\x12\x1d\n\x15\x63rash_server_view_url\x18\x02 \x01(\t\"\xc6\x02\n\x06\x43onfig\x12\x35\n\x03\x62ot\x18\x01 \x01(\x0b\x32(.test_platform.phosphorus.BotEnvironment\x12\x37\n\x04task\x18\x02 \x01(\x0b\x32).test_platform.phosphorus.TaskEnvironment\x12I\n\x14log_data_upload_step\x18\x03 \x01(\x0b\x32+.test_platform.phosphorus.LogDataUploadStep\x12\x46\n\x12\x66\x65tch_crashes_step\x18\x04 \x01(\x0b\x32*.test_platform.phosphorus.FetchCrashesStep\x12\x39\n\x0bprejob_step\x18\x05 \x01(\x0b\x32$.test_platform.phosphorus.PrejobStepBDZBgo.chromium.org/chromiumos/infra/proto/go/test_platform/phosphorusb\x06proto3'
+  serialized_pb=b'\n%test_platform/phosphorus/common.proto\x12\x18test_platform.phosphorus\"&\n\x0e\x42otEnvironment\x12\x14\n\x0c\x61utotest_dir\x18\x01 \x01(\t\"|\n\x0fTaskEnvironment\x12\x13\n\x0bresults_dir\x18\x02 \x01(\t\x12\x18\n\x10test_results_dir\x18\x03 \x01(\t\x12\x1b\n\x13ssp_base_image_name\x18\x04 \x01(\tJ\x04\x08\x01\x10\x02R\x17synchronous_offload_dir\"\xb2\x01\n\nPrejobStep\x12R\n\x18provision_dut_experiment\x18\x01 \x01(\x0b\x32\x30.test_platform.phosphorus.ProvisionDutExperiment\x12P\n\x17\x64ut_topology_experiment\x18\x02 \x01(\x0b\x32/.test_platform.phosphorus.DutTopologyExperiment\"\xc0\x02\n\x16ProvisionDutExperiment\x12\x0f\n\x07\x65nabled\x18\x01 \x01(\x08\x12g\n\x17\x63ros_version_allow_list\x18\x02 \x01(\x0b\x32\x44.test_platform.phosphorus.ProvisionDutExperiment.CrosVersionSelectorH\x00\x12j\n\x1a\x63ros_version_disallow_list\x18\x03 \x01(\x0b\x32\x44.test_platform.phosphorus.ProvisionDutExperiment.CrosVersionSelectorH\x00\x1a\'\n\x13\x43rosVersionSelector\x12\x10\n\x08prefixes\x18\x01 \x03(\tB\x17\n\x15\x63ros_version_selector\"Y\n\x15\x44utTopologyExperiment\x12\x0f\n\x07\x65nabled\x18\x01 \x01(\x08\x12\x16\n\x0etest_allowlist\x18\x02 \x03(\t\x12\x17\n\x0fsuite_allowlist\x18\x03 \x03(\t\"3\n\x11LogDataUploadStep\x12\x1e\n\x16max_concurrent_uploads\x18\x01 \x01(\x05\"R\n\x10\x46\x65tchCrashesStep\x12\x1f\n\x17\x63rash_server_report_url\x18\x01 \x01(\t\x12\x1d\n\x15\x63rash_server_view_url\x18\x02 \x01(\t\"\xc6\x02\n\x06\x43onfig\x12\x35\n\x03\x62ot\x18\x01 \x01(\x0b\x32(.test_platform.phosphorus.BotEnvironment\x12\x37\n\x04task\x18\x02 \x01(\x0b\x32).test_platform.phosphorus.TaskEnvironment\x12I\n\x14log_data_upload_step\x18\x03 \x01(\x0b\x32+.test_platform.phosphorus.LogDataUploadStep\x12\x46\n\x12\x66\x65tch_crashes_step\x18\x04 \x01(\x0b\x32*.test_platform.phosphorus.FetchCrashesStep\x12\x39\n\x0bprejob_step\x18\x05 \x01(\x0b\x32$.test_platform.phosphorus.PrejobStepBDZBgo.chromium.org/chromiumos/infra/proto/go/test_platform/phosphorusb\x06proto3'
 )
 
 
@@ -114,6 +114,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='dut_topology_experiment', full_name='test_platform.phosphorus.PrejobStep.dut_topology_experiment', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -126,8 +133,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=233,
-  serialized_end=329,
+  serialized_start=234,
+  serialized_end=412,
 )
 
 
@@ -157,8 +164,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=588,
-  serialized_end=627,
+  serialized_start=671,
+  serialized_end=710,
 )
 
 _PROVISIONDUTEXPERIMENT = _descriptor.Descriptor(
@@ -204,8 +211,53 @@
       name='cros_version_selector', full_name='test_platform.phosphorus.ProvisionDutExperiment.cros_version_selector',
       index=0, containing_type=None, fields=[]),
   ],
-  serialized_start=332,
-  serialized_end=652,
+  serialized_start=415,
+  serialized_end=735,
+)
+
+
+_DUTTOPOLOGYEXPERIMENT = _descriptor.Descriptor(
+  name='DutTopologyExperiment',
+  full_name='test_platform.phosphorus.DutTopologyExperiment',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='enabled', full_name='test_platform.phosphorus.DutTopologyExperiment.enabled', index=0,
+      number=1, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='test_allowlist', full_name='test_platform.phosphorus.DutTopologyExperiment.test_allowlist', index=1,
+      number=2, type=9, cpp_type=9, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='suite_allowlist', full_name='test_platform.phosphorus.DutTopologyExperiment.suite_allowlist', index=2,
+      number=3, type=9, cpp_type=9, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=737,
+  serialized_end=826,
 )
 
 
@@ -235,8 +287,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=654,
-  serialized_end=705,
+  serialized_start=828,
+  serialized_end=879,
 )
 
 
@@ -273,8 +325,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=707,
-  serialized_end=789,
+  serialized_start=881,
+  serialized_end=963,
 )
 
 
@@ -332,11 +384,12 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=792,
-  serialized_end=1118,
+  serialized_start=966,
+  serialized_end=1292,
 )
 
 _PREJOBSTEP.fields_by_name['provision_dut_experiment'].message_type = _PROVISIONDUTEXPERIMENT
+_PREJOBSTEP.fields_by_name['dut_topology_experiment'].message_type = _DUTTOPOLOGYEXPERIMENT
 _PROVISIONDUTEXPERIMENT_CROSVERSIONSELECTOR.containing_type = _PROVISIONDUTEXPERIMENT
 _PROVISIONDUTEXPERIMENT.fields_by_name['cros_version_allow_list'].message_type = _PROVISIONDUTEXPERIMENT_CROSVERSIONSELECTOR
 _PROVISIONDUTEXPERIMENT.fields_by_name['cros_version_disallow_list'].message_type = _PROVISIONDUTEXPERIMENT_CROSVERSIONSELECTOR
@@ -355,6 +408,7 @@
 DESCRIPTOR.message_types_by_name['TaskEnvironment'] = _TASKENVIRONMENT
 DESCRIPTOR.message_types_by_name['PrejobStep'] = _PREJOBSTEP
 DESCRIPTOR.message_types_by_name['ProvisionDutExperiment'] = _PROVISIONDUTEXPERIMENT
+DESCRIPTOR.message_types_by_name['DutTopologyExperiment'] = _DUTTOPOLOGYEXPERIMENT
 DESCRIPTOR.message_types_by_name['LogDataUploadStep'] = _LOGDATAUPLOADSTEP
 DESCRIPTOR.message_types_by_name['FetchCrashesStep'] = _FETCHCRASHESSTEP
 DESCRIPTOR.message_types_by_name['Config'] = _CONFIG
@@ -396,6 +450,13 @@
 _sym_db.RegisterMessage(ProvisionDutExperiment)
 _sym_db.RegisterMessage(ProvisionDutExperiment.CrosVersionSelector)
 
+DutTopologyExperiment = _reflection.GeneratedProtocolMessageType('DutTopologyExperiment', (_message.Message,), {
+  'DESCRIPTOR' : _DUTTOPOLOGYEXPERIMENT,
+  '__module__' : 'test_platform.phosphorus.common_pb2'
+  # @@protoc_insertion_point(class_scope:test_platform.phosphorus.DutTopologyExperiment)
+  })
+_sym_db.RegisterMessage(DutTopologyExperiment)
+
 LogDataUploadStep = _reflection.GeneratedProtocolMessageType('LogDataUploadStep', (_message.Message,), {
   'DESCRIPTOR' : _LOGDATAUPLOADSTEP,
   '__module__' : 'test_platform.phosphorus.common_pb2'
diff --git a/api/gen_sdk/test_platform/phosphorus/runtest_pb2.py b/api/gen_sdk/test_platform/phosphorus/runtest_pb2.py
index dde83b1..0bb8ff6 100644
--- a/api/gen_sdk/test_platform/phosphorus/runtest_pb2.py
+++ b/api/gen_sdk/test_platform/phosphorus/runtest_pb2.py
@@ -11,6 +11,7 @@
 _sym_db = _symbol_database.Default()
 
 
+from chromite.api.gen_sdk.chromiumos.build.api import container_metadata_pb2 as chromiumos_dot_build_dot_api_dot_container__metadata__pb2
 from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
 from chromite.api.gen_sdk.test_platform.phosphorus import common_pb2 as test__platform_dot_phosphorus_dot_common__pb2
 
@@ -20,9 +21,9 @@
   package='test_platform.phosphorus',
   syntax='proto3',
   serialized_options=b'ZBgo.chromium.org/chromiumos/infra/proto/go/test_platform/phosphorus',
-  serialized_pb=b'\n&test_platform/phosphorus/runtest.proto\x12\x18test_platform.phosphorus\x1a\x1fgoogle/protobuf/timestamp.proto\x1a%test_platform/phosphorus/common.proto\"\xf7\x03\n\x0eRunTestRequest\x12\x30\n\x06\x63onfig\x18\x01 \x01(\x0b\x32 .test_platform.phosphorus.Config\x12\x15\n\rdut_hostnames\x18\x02 \x03(\t\x12\x45\n\x08\x61utotest\x18\x03 \x01(\x0b\x32\x31.test_platform.phosphorus.RunTestRequest.AutotestH\x00\x12,\n\x08\x64\x65\x61\x64line\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x1a\x8b\x02\n\x08\x41utotest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x11\n\ttest_args\x18\x02 \x01(\t\x12\x14\n\x0c\x64isplay_name\x18\x03 \x01(\t\x12\x16\n\x0eis_client_test\x18\x04 \x01(\x08\x12O\n\x07keyvals\x18\x05 \x03(\x0b\x32>.test_platform.phosphorus.RunTestRequest.Autotest.KeyvalsEntry\x12\x11\n\tpeer_duts\x18\x06 \x03(\t\x12\x1c\n\x14image_storage_server\x18\x07 \x01(\t\x1a.\n\x0cKeyvalsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\x06\n\x04testJ\x04\x08\x04\x10\x05R\x0b\x65nvironment\"\xbd\x01\n\x0fRunTestResponse\x12>\n\x05state\x18\x01 \x01(\x0e\x32/.test_platform.phosphorus.RunTestResponse.State\x12\x13\n\x0bresults_dir\x18\x02 \x01(\t\"U\n\x05State\x12\x15\n\x11STATE_UNSPECIFIED\x10\x00\x12\r\n\tSUCCEEDED\x10\x01\x12\n\n\x06\x46\x41ILED\x10\x02\x12\r\n\tTIMED_OUT\x10\x03\x12\x0b\n\x07\x41\x42ORTED\x10\x04\x42\x44ZBgo.chromium.org/chromiumos/infra/proto/go/test_platform/phosphorusb\x06proto3'
+  serialized_pb=b'\n&test_platform/phosphorus/runtest.proto\x12\x18test_platform.phosphorus\x1a-chromiumos/build/api/container_metadata.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a%test_platform/phosphorus/common.proto\"\xbf\x04\n\x0eRunTestRequest\x12\x30\n\x06\x63onfig\x18\x01 \x01(\x0b\x32 .test_platform.phosphorus.Config\x12\x15\n\rdut_hostnames\x18\x02 \x03(\t\x12\x45\n\x08\x61utotest\x18\x03 \x01(\x0b\x32\x31.test_platform.phosphorus.RunTestRequest.AutotestH\x00\x12,\n\x08\x64\x65\x61\x64line\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x46\n\x14\x63ontainer_image_info\x18\x06 \x01(\x0b\x32(.chromiumos.build.api.ContainerImageInfo\x1a\x8b\x02\n\x08\x41utotest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x11\n\ttest_args\x18\x02 \x01(\t\x12\x14\n\x0c\x64isplay_name\x18\x03 \x01(\t\x12\x16\n\x0eis_client_test\x18\x04 \x01(\x08\x12O\n\x07keyvals\x18\x05 \x03(\x0b\x32>.test_platform.phosphorus.RunTestRequest.Autotest.KeyvalsEntry\x12\x11\n\tpeer_duts\x18\x06 \x03(\t\x12\x1c\n\x14image_storage_server\x18\x07 \x01(\t\x1a.\n\x0cKeyvalsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\x06\n\x04testJ\x04\x08\x04\x10\x05R\x0b\x65nvironment\"\xbd\x01\n\x0fRunTestResponse\x12>\n\x05state\x18\x01 \x01(\x0e\x32/.test_platform.phosphorus.RunTestResponse.State\x12\x13\n\x0bresults_dir\x18\x02 \x01(\t\"U\n\x05State\x12\x15\n\x11STATE_UNSPECIFIED\x10\x00\x12\r\n\tSUCCEEDED\x10\x01\x12\n\n\x06\x46\x41ILED\x10\x02\x12\r\n\tTIMED_OUT\x10\x03\x12\x0b\n\x07\x41\x42ORTED\x10\x04\x42\x44ZBgo.chromium.org/chromiumos/infra/proto/go/test_platform/phosphorusb\x06proto3'
   ,
-  dependencies=[google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,test__platform_dot_phosphorus_dot_common__pb2.DESCRIPTOR,])
+  dependencies=[chromiumos_dot_build_dot_api_dot_container__metadata__pb2.DESCRIPTOR,google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,test__platform_dot_phosphorus_dot_common__pb2.DESCRIPTOR,])
 
 
 
@@ -55,8 +56,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=751,
-  serialized_end=836,
+  serialized_start=870,
+  serialized_end=955,
 )
 _sym_db.RegisterEnumDescriptor(_RUNTESTRESPONSE_STATE)
 
@@ -94,8 +95,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=571,
-  serialized_end=617,
+  serialized_start=690,
+  serialized_end=736,
 )
 
 _RUNTESTREQUEST_AUTOTEST = _descriptor.Descriptor(
@@ -166,8 +167,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=350,
-  serialized_end=617,
+  serialized_start=469,
+  serialized_end=736,
 )
 
 _RUNTESTREQUEST = _descriptor.Descriptor(
@@ -205,6 +206,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='container_image_info', full_name='test_platform.phosphorus.RunTestRequest.container_image_info', index=4,
+      number=6, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -220,8 +228,8 @@
       name='test', full_name='test_platform.phosphorus.RunTestRequest.test',
       index=0, containing_type=None, fields=[]),
   ],
-  serialized_start=141,
-  serialized_end=644,
+  serialized_start=188,
+  serialized_end=763,
 )
 
 
@@ -259,8 +267,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=647,
-  serialized_end=836,
+  serialized_start=766,
+  serialized_end=955,
 )
 
 _RUNTESTREQUEST_AUTOTEST_KEYVALSENTRY.containing_type = _RUNTESTREQUEST_AUTOTEST
@@ -269,6 +277,7 @@
 _RUNTESTREQUEST.fields_by_name['config'].message_type = test__platform_dot_phosphorus_dot_common__pb2._CONFIG
 _RUNTESTREQUEST.fields_by_name['autotest'].message_type = _RUNTESTREQUEST_AUTOTEST
 _RUNTESTREQUEST.fields_by_name['deadline'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP
+_RUNTESTREQUEST.fields_by_name['container_image_info'].message_type = chromiumos_dot_build_dot_api_dot_container__metadata__pb2._CONTAINERIMAGEINFO
 _RUNTESTREQUEST.oneofs_by_name['test'].fields.append(
   _RUNTESTREQUEST.fields_by_name['autotest'])
 _RUNTESTREQUEST.fields_by_name['autotest'].containing_oneof = _RUNTESTREQUEST.oneofs_by_name['test']
diff --git a/api/gen_sdk/test_platform/request_pb2.py b/api/gen_sdk/test_platform/request_pb2.py
index df11ec8..17751fb 100644
--- a/api/gen_sdk/test_platform/request_pb2.py
+++ b/api/gen_sdk/test_platform/request_pb2.py
@@ -22,7 +22,7 @@
   package='test_platform',
   syntax='proto3',
   serialized_options=b'Z7go.chromium.org/chromiumos/infra/proto/go/test_platform',
-  serialized_pb=b'\n\x1btest_platform/request.proto\x12\rtest_platform\x1a chromite/api/test_metadata.proto\x1a\x17\x63hromiumos/common.proto\x1a\x1egoogle/protobuf/duration.proto\x1a#test_platform/execution/param.proto\"\xa3\x19\n\x07Request\x12-\n\x06params\x18\x01 \x01(\x0b\x32\x1d.test_platform.Request.Params\x12\x32\n\ttest_plan\x18\x05 \x01(\x0b\x32\x1f.test_platform.Request.TestPlan\x1a\xfb\x12\n\x06Params\x12M\n\x13hardware_attributes\x18\x01 \x01(\x0b\x32\x30.test_platform.Request.Params.HardwareAttributes\x12M\n\x13software_attributes\x18\x02 \x01(\x0b\x32\x30.test_platform.Request.Params.SoftwareAttributes\x12M\n\x13\x66reeform_attributes\x18\t \x01(\x0b\x32\x30.test_platform.Request.Params.FreeformAttributes\x12O\n\x15software_dependencies\x18\x03 \x03(\x0b\x32\x30.test_platform.Request.Params.SoftwareDependency\x12H\n\x11secondary_devices\x18\x0e \x03(\x0b\x32-.test_platform.Request.Params.SecondaryDevice\x12<\n\nscheduling\x18\x04 \x01(\x0b\x32(.test_platform.Request.Params.Scheduling\x12\x32\n\x05retry\x18\x05 \x01(\x0b\x32#.test_platform.Request.Params.Retry\x12\x38\n\x08metadata\x18\x06 \x01(\x0b\x32&.test_platform.Request.Params.Metadata\x12\x30\n\x04time\x18\x07 \x01(\x0b\x32\".test_platform.Request.Params.Time\x12>\n\x0b\x64\x65\x63orations\x18\x08 \x01(\x0b\x32).test_platform.Request.Params.Decorations\x12<\n\nmigrations\x18\x0c \x01(\x0b\x32(.test_platform.Request.Params.Migrations\x12\x37\n\x0f\x65xecution_param\x18\r \x01(\x0b\x32\x1e.test_platform.execution.Param\x1a#\n\x12HardwareAttributes\x12\r\n\x05model\x18\x01 \x01(\t\x1a\x43\n\x12SoftwareAttributes\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x1a\x31\n\x12\x46reeformAttributes\x12\x1b\n\x13swarming_dimensions\x18\x01 \x03(\t\x1a\xaf\x01\n\x12SoftwareDependency\x12\x18\n\x0e\x63hromeos_build\x18\x03 \x01(\tH\x00\x12#\n\x19\x63hromeos_build_gcs_bucket\x18\x07 \x01(\tH\x00\x12\x1b\n\x11ro_firmware_build\x18\x04 \x01(\tH\x00\x12\x1b\n\x11rw_firmware_build\x18\x05 \x01(\tH\x00\x12\x19\n\x0flacros_gcs_path\x18\x06 \x01(\tH\x00\x42\x05\n\x03\x64\x65p\x1a\x80\x02\n\x0fSecondaryDevice\x12M\n\x13software_attributes\x18\x01 \x01(\x0b\x32\x30.test_platform.Request.Params.SoftwareAttributes\x12M\n\x13hardware_attributes\x18\x02 \x01(\x0b\x32\x30.test_platform.Request.Params.HardwareAttributes\x12O\n\x15software_dependencies\x18\x03 \x03(\x0b\x32\x30.test_platform.Request.Params.SoftwareDependency\x1a\x9e\x03\n\nScheduling\x12L\n\x0cmanaged_pool\x18\x01 \x01(\x0e\x32\x34.test_platform.Request.Params.Scheduling.ManagedPoolH\x00\x12\x18\n\x0eunmanaged_pool\x18\x02 \x01(\tH\x00\x12\x10\n\x08priority\x18\x04 \x01(\x03\x12\x12\n\nqs_account\x18\x05 \x01(\t\"\xf9\x01\n\x0bManagedPool\x12\x1c\n\x18MANAGED_POOL_UNSPECIFIED\x10\x00\x12\x13\n\x0fMANAGED_POOL_CQ\x10\x01\x12\x14\n\x10MANAGED_POOL_BVT\x10\x02\x12\x17\n\x13MANAGED_POOL_SUITES\x10\x03\x12\x14\n\x10MANAGED_POOL_CTS\x10\x04\x12\x1d\n\x19MANAGED_POOL_CTS_PERBUILD\x10\x05\x12\x1b\n\x17MANAGED_POOL_CONTINUOUS\x10\x06\x12\x1e\n\x1aMANAGED_POOL_ARC_PRESUBMIT\x10\x07\x12\x16\n\x12MANAGED_POOL_QUOTA\x10\x08\x42\x06\n\x04pool\x1a#\n\x05Retry\x12\r\n\x05\x61llow\x18\x01 \x01(\x08\x12\x0b\n\x03max\x18\x02 \x01(\x05\x1aH\n\x08Metadata\x12\x19\n\x11test_metadata_url\x18\x01 \x01(\t\x12!\n\x19\x64\x65\x62ug_symbols_archive_url\x18\x02 \x01(\t\x1a;\n\x04Time\x12\x33\n\x10maximum_duration\x18\x01 \x01(\x0b\x32\x19.google.protobuf.Duration\x1a\xaa\x02\n\x0b\x44\x65\x63orations\x12X\n\x10\x61utotest_keyvals\x18\x01 \x03(\x0b\x32>.test_platform.Request.Params.Decorations.AutotestKeyvalsEntry\x12\x0c\n\x04tags\x18\x02 \x03(\t\x12J\n\ttest_args\x18\x03 \x03(\x0b\x32\x37.test_platform.Request.Params.Decorations.TestArgsEntry\x1a\x36\n\x14\x41utotestKeyvalsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a/\n\rTestArgsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\x65\n\nMigrationsJ\x04\x08\x01\x10\x02J\x04\x08\x02\x10\x03J\x04\x08\x03\x10\x04R\x0fuse_test_runnerR\x1a\x65nable_synchronous_offloadR\x18notificationless_offloadJ\x04\x08\x0b\x10\x0cJ\x04\x08\n\x10\x0bR\rnotificationsR\x06legacy\x1a\x15\n\x05Suite\x12\x0c\n\x04name\x18\x01 \x01(\t\x1a\x8e\x01\n\x04Test\x12\x38\n\x08\x61utotest\x18\x01 \x01(\x0b\x32$.test_platform.Request.Test.AutotestH\x00\x1a\x41\n\x08\x41utotest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x11\n\ttest_args\x18\x02 \x01(\t\x12\x14\n\x0c\x64isplay_name\x18\x03 \x01(\tB\t\n\x07harness\x1a\xe4\x02\n\x0b\x45numeration\x12S\n\x14\x61utotest_invocations\x18\x02 \x03(\x0b\x32\x35.test_platform.Request.Enumeration.AutotestInvocation\x1a\xff\x01\n\x12\x41utotestInvocation\x12(\n\x04test\x18\x01 \x01(\x0b\x32\x1a.chromite.api.AutotestTest\x12\x11\n\ttest_args\x18\x02 \x01(\t\x12\x14\n\x0c\x64isplay_name\x18\x03 \x01(\t\x12`\n\x0eresult_keyvals\x18\x04 \x03(\x0b\x32H.test_platform.Request.Enumeration.AutotestInvocation.ResultKeyvalsEntry\x1a\x34\n\x12ResultKeyvalsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\x9b\x01\n\x08TestPlan\x12+\n\x05suite\x18\x01 \x03(\x0b\x32\x1c.test_platform.Request.Suite\x12)\n\x04test\x18\x02 \x03(\x0b\x32\x1b.test_platform.Request.Test\x12\x37\n\x0b\x65numeration\x18\x03 \x01(\x0b\x32\".test_platform.Request.EnumerationJ\x04\x08\x06\x10\x07J\x04\x08\x07\x10\x08\x42\x39Z7go.chromium.org/chromiumos/infra/proto/go/test_platformb\x06proto3'
+  serialized_pb=b'\n\x1btest_platform/request.proto\x12\rtest_platform\x1a chromite/api/test_metadata.proto\x1a\x17\x63hromiumos/common.proto\x1a\x1egoogle/protobuf/duration.proto\x1a#test_platform/execution/param.proto\"\xeb\x1a\n\x07Request\x12-\n\x06params\x18\x01 \x01(\x0b\x32\x1d.test_platform.Request.Params\x12\x32\n\ttest_plan\x18\x05 \x01(\x0b\x32\x1f.test_platform.Request.TestPlan\x1a\xc3\x14\n\x06Params\x12M\n\x13hardware_attributes\x18\x01 \x01(\x0b\x32\x30.test_platform.Request.Params.HardwareAttributes\x12M\n\x13software_attributes\x18\x02 \x01(\x0b\x32\x30.test_platform.Request.Params.SoftwareAttributes\x12M\n\x13\x66reeform_attributes\x18\t \x01(\x0b\x32\x30.test_platform.Request.Params.FreeformAttributes\x12O\n\x15software_dependencies\x18\x03 \x03(\x0b\x32\x30.test_platform.Request.Params.SoftwareDependency\x12H\n\x11secondary_devices\x18\x0e \x03(\x0b\x32-.test_platform.Request.Params.SecondaryDevice\x12<\n\nscheduling\x18\x04 \x01(\x0b\x32(.test_platform.Request.Params.Scheduling\x12\x32\n\x05retry\x18\x05 \x01(\x0b\x32#.test_platform.Request.Params.Retry\x12\x38\n\x08metadata\x18\x06 \x01(\x0b\x32&.test_platform.Request.Params.Metadata\x12\x30\n\x04time\x18\x07 \x01(\x0b\x32\".test_platform.Request.Params.Time\x12>\n\x0b\x64\x65\x63orations\x18\x08 \x01(\x0b\x32).test_platform.Request.Params.Decorations\x12<\n\nmigrations\x18\x0c \x01(\x0b\x32(.test_platform.Request.Params.Migrations\x12\x37\n\x0f\x65xecution_param\x18\r \x01(\x0b\x32\x1e.test_platform.execution.Param\x12T\n\x17test_execution_behavior\x18\x0f \x01(\x0e\x32\x33.test_platform.Request.Params.TestExecutionBehavior\x1a\x42\n\x12HardwareAttributes\x12\r\n\x05model\x18\x01 \x01(\t\x12\x1d\n\x15require_stable_device\x18\x02 \x01(\x08\x1a\x43\n\x12SoftwareAttributes\x12-\n\x0c\x62uild_target\x18\x02 \x01(\x0b\x32\x17.chromiumos.BuildTarget\x1a\x31\n\x12\x46reeformAttributes\x12\x1b\n\x13swarming_dimensions\x18\x01 \x03(\t\x1a\xaf\x01\n\x12SoftwareDependency\x12\x18\n\x0e\x63hromeos_build\x18\x03 \x01(\tH\x00\x12#\n\x19\x63hromeos_build_gcs_bucket\x18\x07 \x01(\tH\x00\x12\x1b\n\x11ro_firmware_build\x18\x04 \x01(\tH\x00\x12\x1b\n\x11rw_firmware_build\x18\x05 \x01(\tH\x00\x12\x19\n\x0flacros_gcs_path\x18\x06 \x01(\tH\x00\x42\x05\n\x03\x64\x65p\x1a\x80\x02\n\x0fSecondaryDevice\x12M\n\x13software_attributes\x18\x01 \x01(\x0b\x32\x30.test_platform.Request.Params.SoftwareAttributes\x12M\n\x13hardware_attributes\x18\x02 \x01(\x0b\x32\x30.test_platform.Request.Params.HardwareAttributes\x12O\n\x15software_dependencies\x18\x03 \x03(\x0b\x32\x30.test_platform.Request.Params.SoftwareDependency\x1a\x9e\x03\n\nScheduling\x12L\n\x0cmanaged_pool\x18\x01 \x01(\x0e\x32\x34.test_platform.Request.Params.Scheduling.ManagedPoolH\x00\x12\x18\n\x0eunmanaged_pool\x18\x02 \x01(\tH\x00\x12\x10\n\x08priority\x18\x04 \x01(\x03\x12\x12\n\nqs_account\x18\x05 \x01(\t\"\xf9\x01\n\x0bManagedPool\x12\x1c\n\x18MANAGED_POOL_UNSPECIFIED\x10\x00\x12\x13\n\x0fMANAGED_POOL_CQ\x10\x01\x12\x14\n\x10MANAGED_POOL_BVT\x10\x02\x12\x17\n\x13MANAGED_POOL_SUITES\x10\x03\x12\x14\n\x10MANAGED_POOL_CTS\x10\x04\x12\x1d\n\x19MANAGED_POOL_CTS_PERBUILD\x10\x05\x12\x1b\n\x17MANAGED_POOL_CONTINUOUS\x10\x06\x12\x1e\n\x1aMANAGED_POOL_ARC_PRESUBMIT\x10\x07\x12\x16\n\x12MANAGED_POOL_QUOTA\x10\x08\x42\x06\n\x04pool\x1a#\n\x05Retry\x12\r\n\x05\x61llow\x18\x01 \x01(\x08\x12\x0b\n\x03max\x18\x02 \x01(\x05\x1aH\n\x08Metadata\x12\x19\n\x11test_metadata_url\x18\x01 \x01(\t\x12!\n\x19\x64\x65\x62ug_symbols_archive_url\x18\x02 \x01(\t\x1a;\n\x04Time\x12\x33\n\x10maximum_duration\x18\x01 \x01(\x0b\x32\x19.google.protobuf.Duration\x1a\xaa\x02\n\x0b\x44\x65\x63orations\x12X\n\x10\x61utotest_keyvals\x18\x01 \x03(\x0b\x32>.test_platform.Request.Params.Decorations.AutotestKeyvalsEntry\x12\x0c\n\x04tags\x18\x02 \x03(\t\x12J\n\ttest_args\x18\x03 \x03(\x0b\x32\x37.test_platform.Request.Params.Decorations.TestArgsEntry\x1a\x36\n\x14\x41utotestKeyvalsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a/\n\rTestArgsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\x65\n\nMigrationsJ\x04\x08\x01\x10\x02J\x04\x08\x02\x10\x03J\x04\x08\x03\x10\x04R\x0fuse_test_runnerR\x1a\x65nable_synchronous_offloadR\x18notificationless_offload\"Q\n\x15TestExecutionBehavior\x12\x18\n\x14\x42\x45HAVIOR_UNSPECIFIED\x10\x00\x12\x0c\n\x08\x43RITICAL\x10\x01\x12\x10\n\x0cNON_CRITICAL\x10\x02J\x04\x08\x0b\x10\x0cJ\x04\x08\n\x10\x0bR\rnotificationsR\x06legacy\x1a\x15\n\x05Suite\x12\x0c\n\x04name\x18\x01 \x01(\t\x1a\x8e\x01\n\x04Test\x12\x38\n\x08\x61utotest\x18\x01 \x01(\x0b\x32$.test_platform.Request.Test.AutotestH\x00\x1a\x41\n\x08\x41utotest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x11\n\ttest_args\x18\x02 \x01(\t\x12\x14\n\x0c\x64isplay_name\x18\x03 \x01(\tB\t\n\x07harness\x1a\xe4\x02\n\x0b\x45numeration\x12S\n\x14\x61utotest_invocations\x18\x02 \x03(\x0b\x32\x35.test_platform.Request.Enumeration.AutotestInvocation\x1a\xff\x01\n\x12\x41utotestInvocation\x12(\n\x04test\x18\x01 \x01(\x0b\x32\x1a.chromite.api.AutotestTest\x12\x11\n\ttest_args\x18\x02 \x01(\t\x12\x14\n\x0c\x64isplay_name\x18\x03 \x01(\t\x12`\n\x0eresult_keyvals\x18\x04 \x03(\x0b\x32H.test_platform.Request.Enumeration.AutotestInvocation.ResultKeyvalsEntry\x1a\x34\n\x12ResultKeyvalsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\x9b\x01\n\x08TestPlan\x12+\n\x05suite\x18\x01 \x03(\x0b\x32\x1c.test_platform.Request.Suite\x12)\n\x04test\x18\x02 \x03(\x0b\x32\x1b.test_platform.Request.Test\x12\x37\n\x0b\x65numeration\x18\x03 \x01(\x0b\x32\".test_platform.Request.EnumerationJ\x04\x08\x06\x10\x07J\x04\x08\x07\x10\x08\x42\x39Z7go.chromium.org/chromiumos/infra/proto/go/test_platformb\x06proto3'
   ,
   dependencies=[chromite_dot_api_dot_test__metadata__pb2.DESCRIPTOR,chromiumos_dot_common__pb2.DESCRIPTOR,google_dot_protobuf_dot_duration__pb2.DESCRIPTOR,test__platform_dot_execution_dot_param__pb2.DESCRIPTOR,])
 
@@ -73,11 +73,37 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=1845,
-  serialized_end=2094,
+  serialized_start=1962,
+  serialized_end=2211,
 )
 _sym_db.RegisterEnumDescriptor(_REQUEST_PARAMS_SCHEDULING_MANAGEDPOOL)
 
+_REQUEST_PARAMS_TESTEXECUTIONBEHAVIOR = _descriptor.EnumDescriptor(
+  name='TestExecutionBehavior',
+  full_name='test_platform.Request.Params.TestExecutionBehavior',
+  filename=None,
+  file=DESCRIPTOR,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='BEHAVIOR_UNSPECIFIED', index=0, number=0,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='CRITICAL', index=1, number=1,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='NON_CRITICAL', index=2, number=2,
+      serialized_options=None,
+      type=None),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=2797,
+  serialized_end=2878,
+)
+_sym_db.RegisterEnumDescriptor(_REQUEST_PARAMS_TESTEXECUTIONBEHAVIOR)
+
 
 _REQUEST_PARAMS_HARDWAREATTRIBUTES = _descriptor.Descriptor(
   name='HardwareAttributes',
@@ -93,6 +119,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='require_stable_device', full_name='test_platform.Request.Params.HardwareAttributes.require_stable_device', index=1,
+      number=2, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -105,8 +138,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1093,
-  serialized_end=1128,
+  serialized_start=1179,
+  serialized_end=1245,
 )
 
 _REQUEST_PARAMS_SOFTWAREATTRIBUTES = _descriptor.Descriptor(
@@ -135,8 +168,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1130,
-  serialized_end=1197,
+  serialized_start=1247,
+  serialized_end=1314,
 )
 
 _REQUEST_PARAMS_FREEFORMATTRIBUTES = _descriptor.Descriptor(
@@ -165,8 +198,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1199,
-  serialized_end=1248,
+  serialized_start=1316,
+  serialized_end=1365,
 )
 
 _REQUEST_PARAMS_SOFTWAREDEPENDENCY = _descriptor.Descriptor(
@@ -226,8 +259,8 @@
       name='dep', full_name='test_platform.Request.Params.SoftwareDependency.dep',
       index=0, containing_type=None, fields=[]),
   ],
-  serialized_start=1251,
-  serialized_end=1426,
+  serialized_start=1368,
+  serialized_end=1543,
 )
 
 _REQUEST_PARAMS_SECONDARYDEVICE = _descriptor.Descriptor(
@@ -270,8 +303,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1429,
-  serialized_end=1685,
+  serialized_start=1546,
+  serialized_end=1802,
 )
 
 _REQUEST_PARAMS_SCHEDULING = _descriptor.Descriptor(
@@ -325,8 +358,8 @@
       name='pool', full_name='test_platform.Request.Params.Scheduling.pool',
       index=0, containing_type=None, fields=[]),
   ],
-  serialized_start=1688,
-  serialized_end=2102,
+  serialized_start=1805,
+  serialized_end=2219,
 )
 
 _REQUEST_PARAMS_RETRY = _descriptor.Descriptor(
@@ -362,8 +395,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2104,
-  serialized_end=2139,
+  serialized_start=2221,
+  serialized_end=2256,
 )
 
 _REQUEST_PARAMS_METADATA = _descriptor.Descriptor(
@@ -399,8 +432,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2141,
-  serialized_end=2213,
+  serialized_start=2258,
+  serialized_end=2330,
 )
 
 _REQUEST_PARAMS_TIME = _descriptor.Descriptor(
@@ -429,8 +462,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2215,
-  serialized_end=2274,
+  serialized_start=2332,
+  serialized_end=2391,
 )
 
 _REQUEST_PARAMS_DECORATIONS_AUTOTESTKEYVALSENTRY = _descriptor.Descriptor(
@@ -466,8 +499,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2472,
-  serialized_end=2526,
+  serialized_start=2589,
+  serialized_end=2643,
 )
 
 _REQUEST_PARAMS_DECORATIONS_TESTARGSENTRY = _descriptor.Descriptor(
@@ -503,8 +536,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2528,
-  serialized_end=2575,
+  serialized_start=2645,
+  serialized_end=2692,
 )
 
 _REQUEST_PARAMS_DECORATIONS = _descriptor.Descriptor(
@@ -547,8 +580,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2277,
-  serialized_end=2575,
+  serialized_start=2394,
+  serialized_end=2692,
 )
 
 _REQUEST_PARAMS_MIGRATIONS = _descriptor.Descriptor(
@@ -570,8 +603,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2577,
-  serialized_end=2678,
+  serialized_start=2694,
+  serialized_end=2795,
 )
 
 _REQUEST_PARAMS = _descriptor.Descriptor(
@@ -665,11 +698,19 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='test_execution_behavior', full_name='test_platform.Request.Params.test_execution_behavior', index=12,
+      number=15, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
   nested_types=[_REQUEST_PARAMS_HARDWAREATTRIBUTES, _REQUEST_PARAMS_SOFTWAREATTRIBUTES, _REQUEST_PARAMS_FREEFORMATTRIBUTES, _REQUEST_PARAMS_SOFTWAREDEPENDENCY, _REQUEST_PARAMS_SECONDARYDEVICE, _REQUEST_PARAMS_SCHEDULING, _REQUEST_PARAMS_RETRY, _REQUEST_PARAMS_METADATA, _REQUEST_PARAMS_TIME, _REQUEST_PARAMS_DECORATIONS, _REQUEST_PARAMS_MIGRATIONS, ],
   enum_types=[
+    _REQUEST_PARAMS_TESTEXECUTIONBEHAVIOR,
   ],
   serialized_options=None,
   is_extendable=False,
@@ -678,7 +719,7 @@
   oneofs=[
   ],
   serialized_start=286,
-  serialized_end=2713,
+  serialized_end=2913,
 )
 
 _REQUEST_SUITE = _descriptor.Descriptor(
@@ -707,8 +748,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2715,
-  serialized_end=2736,
+  serialized_start=2915,
+  serialized_end=2936,
 )
 
 _REQUEST_TEST_AUTOTEST = _descriptor.Descriptor(
@@ -751,8 +792,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2805,
-  serialized_end=2870,
+  serialized_start=3005,
+  serialized_end=3070,
 )
 
 _REQUEST_TEST = _descriptor.Descriptor(
@@ -784,8 +825,8 @@
       name='harness', full_name='test_platform.Request.Test.harness',
       index=0, containing_type=None, fields=[]),
   ],
-  serialized_start=2739,
-  serialized_end=2881,
+  serialized_start=2939,
+  serialized_end=3081,
 )
 
 _REQUEST_ENUMERATION_AUTOTESTINVOCATION_RESULTKEYVALSENTRY = _descriptor.Descriptor(
@@ -821,8 +862,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3188,
-  serialized_end=3240,
+  serialized_start=3388,
+  serialized_end=3440,
 )
 
 _REQUEST_ENUMERATION_AUTOTESTINVOCATION = _descriptor.Descriptor(
@@ -872,8 +913,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2985,
-  serialized_end=3240,
+  serialized_start=3185,
+  serialized_end=3440,
 )
 
 _REQUEST_ENUMERATION = _descriptor.Descriptor(
@@ -902,8 +943,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2884,
-  serialized_end=3240,
+  serialized_start=3084,
+  serialized_end=3440,
 )
 
 _REQUEST_TESTPLAN = _descriptor.Descriptor(
@@ -946,8 +987,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3243,
-  serialized_end=3398,
+  serialized_start=3443,
+  serialized_end=3598,
 )
 
 _REQUEST = _descriptor.Descriptor(
@@ -984,7 +1025,7 @@
   oneofs=[
   ],
   serialized_start=175,
-  serialized_end=3410,
+  serialized_end=3610,
 )
 
 _REQUEST_PARAMS_HARDWAREATTRIBUTES.containing_type = _REQUEST_PARAMS
@@ -1042,7 +1083,9 @@
 _REQUEST_PARAMS.fields_by_name['decorations'].message_type = _REQUEST_PARAMS_DECORATIONS
 _REQUEST_PARAMS.fields_by_name['migrations'].message_type = _REQUEST_PARAMS_MIGRATIONS
 _REQUEST_PARAMS.fields_by_name['execution_param'].message_type = test__platform_dot_execution_dot_param__pb2._PARAM
+_REQUEST_PARAMS.fields_by_name['test_execution_behavior'].enum_type = _REQUEST_PARAMS_TESTEXECUTIONBEHAVIOR
 _REQUEST_PARAMS.containing_type = _REQUEST
+_REQUEST_PARAMS_TESTEXECUTIONBEHAVIOR.containing_type = _REQUEST_PARAMS
 _REQUEST_SUITE.containing_type = _REQUEST
 _REQUEST_TEST_AUTOTEST.containing_type = _REQUEST_TEST
 _REQUEST_TEST.fields_by_name['autotest'].message_type = _REQUEST_TEST_AUTOTEST
diff --git a/api/gen_sdk/test_platform/skylab_test_runner/request_pb2.py b/api/gen_sdk/test_platform/skylab_test_runner/request_pb2.py
index e2ce165..595d8f8 100644
--- a/api/gen_sdk/test_platform/skylab_test_runner/request_pb2.py
+++ b/api/gen_sdk/test_platform/skylab_test_runner/request_pb2.py
@@ -11,6 +11,7 @@
 _sym_db = _symbol_database.Default()
 
 
+from chromite.api.gen_sdk.chromiumos.build.api import container_metadata_pb2 as chromiumos_dot_build_dot_api_dot_container__metadata__pb2
 from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
 from chromite.api.gen_sdk.test_platform.execution import param_pb2 as test__platform_dot_execution_dot_param__pb2
 from chromite.api.gen_sdk.test_platform import request_pb2 as test__platform_dot_request__pb2
@@ -21,9 +22,9 @@
   package='test_platform.skylab_test_runner',
   syntax='proto3',
   serialized_options=b'ZJgo.chromium.org/chromiumos/infra/proto/go/test_platform/skylab_test_runner',
-  serialized_pb=b'\n.test_platform/skylab_test_runner/request.proto\x12 test_platform.skylab_test_runner\x1a\x1fgoogle/protobuf/timestamp.proto\x1a#test_platform/execution/param.proto\x1a\x1btest_platform/request.proto\"\x8b\x0b\n\x07Request\x12@\n\x06prejob\x18\x01 \x01(\x0b\x32\x30.test_platform.skylab_test_runner.Request.Prejob\x12<\n\x04test\x18\x02 \x01(\x0b\x32..test_platform.skylab_test_runner.Request.Test\x12,\n\x08\x64\x65\x61\x64line\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x1a\n\x12parent_request_uid\x18\x04 \x01(\t\x12\x17\n\x0fparent_build_id\x18\x05 \x01(\x03\x12\x43\n\x05tests\x18\x06 \x03(\x0b\x32\x34.test_platform.skylab_test_runner.Request.TestsEntry\x12\x37\n\x0f\x65xecution_param\x18\x07 \x01(\x0b\x32\x1e.test_platform.execution.Param\x1a\xfb\x03\n\x06Prejob\x12O\n\x15software_dependencies\x18\x01 \x03(\x0b\x32\x30.test_platform.Request.Params.SoftwareDependency\x12k\n\x14provisionable_labels\x18\x02 \x03(\x0b\x32I.test_platform.skylab_test_runner.Request.Prejob.ProvisionableLabelsEntryB\x02\x18\x01\x12\x0f\n\x07use_tls\x18\x03 \x01(\x08\x12M\n\x13software_attributes\x18\x04 \x01(\x0b\x32\x30.test_platform.Request.Params.SoftwareAttributes\x12M\n\x13hardware_attributes\x18\x05 \x01(\x0b\x32\x30.test_platform.Request.Params.HardwareAttributes\x12H\n\x11secondary_devices\x18\x06 \x03(\x0b\x32-.test_platform.Request.Params.SecondaryDevice\x1a:\n\x18ProvisionableLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\xc2\x03\n\x04Test\x12K\n\x08\x61utotest\x18\x01 \x01(\x0b\x32\x37.test_platform.skylab_test_runner.Request.Test.AutotestH\x00\x12N\n\x07offload\x18\x02 \x01(\x0b\x32=.test_platform.skylab_test_runner.Request.Test.OffloadOptions\x1a\xe0\x01\n\x08\x41utotest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x11\n\ttest_args\x18\x02 \x01(\t\x12U\n\x07keyvals\x18\x03 \x03(\x0b\x32\x44.test_platform.skylab_test_runner.Request.Test.Autotest.KeyvalsEntry\x12\x16\n\x0eis_client_test\x18\x04 \x01(\x08\x12\x14\n\x0c\x64isplay_name\x18\x05 \x01(\t\x1a.\n\x0cKeyvalsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a/\n\x0eOffloadOptions\x12\x1d\n\x15synchronous_gs_enable\x18\x01 \x01(\x08\x42\t\n\x07harness\x1a\\\n\nTestsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12=\n\x05value\x18\x02 \x01(\x0b\x32..test_platform.skylab_test_runner.Request.Test:\x02\x38\x01\x42LZJgo.chromium.org/chromiumos/infra/proto/go/test_platform/skylab_test_runnerb\x06proto3'
+  serialized_pb=b'\n.test_platform/skylab_test_runner/request.proto\x12 test_platform.skylab_test_runner\x1a-chromiumos/build/api/container_metadata.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a#test_platform/execution/param.proto\x1a\x1btest_platform/request.proto\"\xb5\x0c\n\x07Request\x12@\n\x06prejob\x18\x01 \x01(\x0b\x32\x30.test_platform.skylab_test_runner.Request.Prejob\x12<\n\x04test\x18\x02 \x01(\x0b\x32..test_platform.skylab_test_runner.Request.Test\x12,\n\x08\x64\x65\x61\x64line\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x1a\n\x12parent_request_uid\x18\x04 \x01(\t\x12\x17\n\x0fparent_build_id\x18\x05 \x01(\x03\x12\x43\n\x05tests\x18\x06 \x03(\x0b\x32\x34.test_platform.skylab_test_runner.Request.TestsEntry\x12\x37\n\x0f\x65xecution_param\x18\x07 \x01(\x0b\x32\x1e.test_platform.execution.Param\x12J\n\x14\x63ontainer_image_info\x18\x08 \x01(\x0b\x32(.chromiumos.build.api.ContainerImageInfoB\x02\x18\x01\x12\\\n\x1f\x64\x65\x66\x61ult_test_execution_behavior\x18\t \x01(\x0e\x32\x33.test_platform.Request.Params.TestExecutionBehavior\x1a\xfb\x03\n\x06Prejob\x12O\n\x15software_dependencies\x18\x01 \x03(\x0b\x32\x30.test_platform.Request.Params.SoftwareDependency\x12k\n\x14provisionable_labels\x18\x02 \x03(\x0b\x32I.test_platform.skylab_test_runner.Request.Prejob.ProvisionableLabelsEntryB\x02\x18\x01\x12\x0f\n\x07use_tls\x18\x03 \x01(\x08\x12M\n\x13software_attributes\x18\x04 \x01(\x0b\x32\x30.test_platform.Request.Params.SoftwareAttributes\x12M\n\x13hardware_attributes\x18\x05 \x01(\x0b\x32\x30.test_platform.Request.Params.HardwareAttributes\x12H\n\x11secondary_devices\x18\x06 \x03(\x0b\x32-.test_platform.Request.Params.SecondaryDevice\x1a:\n\x18ProvisionableLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\xc2\x03\n\x04Test\x12K\n\x08\x61utotest\x18\x01 \x01(\x0b\x32\x37.test_platform.skylab_test_runner.Request.Test.AutotestH\x00\x12N\n\x07offload\x18\x02 \x01(\x0b\x32=.test_platform.skylab_test_runner.Request.Test.OffloadOptions\x1a\xe0\x01\n\x08\x41utotest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x11\n\ttest_args\x18\x02 \x01(\t\x12U\n\x07keyvals\x18\x03 \x03(\x0b\x32\x44.test_platform.skylab_test_runner.Request.Test.Autotest.KeyvalsEntry\x12\x16\n\x0eis_client_test\x18\x04 \x01(\x08\x12\x14\n\x0c\x64isplay_name\x18\x05 \x01(\t\x1a.\n\x0cKeyvalsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a/\n\x0eOffloadOptions\x12\x1d\n\x15synchronous_gs_enable\x18\x01 \x01(\x08\x42\t\n\x07harness\x1a\\\n\nTestsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12=\n\x05value\x18\x02 \x01(\x0b\x32..test_platform.skylab_test_runner.Request.Test:\x02\x38\x01\x42LZJgo.chromium.org/chromiumos/infra/proto/go/test_platform/skylab_test_runnerb\x06proto3'
   ,
-  dependencies=[google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,test__platform_dot_execution_dot_param__pb2.DESCRIPTOR,test__platform_dot_request__pb2.DESCRIPTOR,])
+  dependencies=[chromiumos_dot_build_dot_api_dot_container__metadata__pb2.DESCRIPTOR,google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,test__platform_dot_execution_dot_param__pb2.DESCRIPTOR,test__platform_dot_request__pb2.DESCRIPTOR,])
 
 
 
@@ -61,8 +62,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=998,
-  serialized_end=1056,
+  serialized_start=1215,
+  serialized_end=1273,
 )
 
 _REQUEST_PREJOB = _descriptor.Descriptor(
@@ -126,8 +127,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=549,
-  serialized_end=1056,
+  serialized_start=766,
+  serialized_end=1273,
 )
 
 _REQUEST_TEST_AUTOTEST_KEYVALSENTRY = _descriptor.Descriptor(
@@ -163,8 +164,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1403,
-  serialized_end=1449,
+  serialized_start=1620,
+  serialized_end=1666,
 )
 
 _REQUEST_TEST_AUTOTEST = _descriptor.Descriptor(
@@ -221,8 +222,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1225,
-  serialized_end=1449,
+  serialized_start=1442,
+  serialized_end=1666,
 )
 
 _REQUEST_TEST_OFFLOADOPTIONS = _descriptor.Descriptor(
@@ -251,8 +252,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1451,
-  serialized_end=1498,
+  serialized_start=1668,
+  serialized_end=1715,
 )
 
 _REQUEST_TEST = _descriptor.Descriptor(
@@ -291,8 +292,8 @@
       name='harness', full_name='test_platform.skylab_test_runner.Request.Test.harness',
       index=0, containing_type=None, fields=[]),
   ],
-  serialized_start=1059,
-  serialized_end=1509,
+  serialized_start=1276,
+  serialized_end=1726,
 )
 
 _REQUEST_TESTSENTRY = _descriptor.Descriptor(
@@ -328,8 +329,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1511,
-  serialized_end=1603,
+  serialized_start=1728,
+  serialized_end=1820,
 )
 
 _REQUEST = _descriptor.Descriptor(
@@ -388,6 +389,20 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='container_image_info', full_name='test_platform.skylab_test_runner.Request.container_image_info', index=7,
+      number=8, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=b'\030\001', file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='default_test_execution_behavior', full_name='test_platform.skylab_test_runner.Request.default_test_execution_behavior', index=8,
+      number=9, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -400,8 +415,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=184,
-  serialized_end=1603,
+  serialized_start=231,
+  serialized_end=1820,
 )
 
 _REQUEST_PREJOB_PROVISIONABLELABELSENTRY.containing_type = _REQUEST_PREJOB
@@ -428,6 +443,8 @@
 _REQUEST.fields_by_name['deadline'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP
 _REQUEST.fields_by_name['tests'].message_type = _REQUEST_TESTSENTRY
 _REQUEST.fields_by_name['execution_param'].message_type = test__platform_dot_execution_dot_param__pb2._PARAM
+_REQUEST.fields_by_name['container_image_info'].message_type = chromiumos_dot_build_dot_api_dot_container__metadata__pb2._CONTAINERIMAGEINFO
+_REQUEST.fields_by_name['default_test_execution_behavior'].enum_type = test__platform_dot_request__pb2._REQUEST_PARAMS_TESTEXECUTIONBEHAVIOR
 DESCRIPTOR.message_types_by_name['Request'] = _REQUEST
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
@@ -500,4 +517,5 @@
 _REQUEST_PREJOB.fields_by_name['provisionable_labels']._options = None
 _REQUEST_TEST_AUTOTEST_KEYVALSENTRY._options = None
 _REQUEST_TESTSENTRY._options = None
+_REQUEST.fields_by_name['container_image_info']._options = None
 # @@protoc_insertion_point(module_scope)
diff --git a/api/gen_sdk/test_platform/v2/request_pb2.py b/api/gen_sdk/test_platform/v2/request_pb2.py
index 5292b1c..1a2f30a 100644
--- a/api/gen_sdk/test_platform/v2/request_pb2.py
+++ b/api/gen_sdk/test_platform/v2/request_pb2.py
@@ -12,19 +12,17 @@
 
 
 from chromite.api.gen_sdk.chromiumos import common_pb2 as chromiumos_dot_common__pb2
-from chromite.api.gen_sdk.chromiumos.test.api import coverage_rule_pb2 as chromiumos_dot_test_dot_api_dot_coverage__rule__pb2
-from chromite.api.gen_sdk.chromiumos.test.api import plan_pb2 as chromiumos_dot_test_dot_api_dot_plan__pb2
-from chromite.api.gen_sdk.chromiumos.test.api import provision_state_pb2 as chromiumos_dot_test_dot_api_dot_provision__state__pb2
+from chromite.api.gen_sdk.chromiumos.test.api.v1 import plan_pb2 as chromiumos_dot_test_dot_api_dot_v1_dot_plan__pb2
 
 
 DESCRIPTOR = _descriptor.FileDescriptor(
   name='test_platform/v2/request.proto',
   package='test_platform.v2',
   syntax='proto3',
-  serialized_options=b'Z:go.chromium.org/chromiumos/infra/proto/go/test_platform/v2',
-  serialized_pb=b'\n\x1etest_platform/v2/request.proto\x12\x10test_platform.v2\x1a\x17\x63hromiumos/common.proto\x1a\'chromiumos/test/api/coverage_rule.proto\x1a\x1e\x63hromiumos/test/api/plan.proto\x1a)chromiumos/test/api/provision_state.proto\"y\n\x08TestSpec\x12,\n\x0f\x62uild_directory\x18\x01 \x01(\x0b\x32\x13.chromiumos.GcsPath\x12\x37\n\x0chw_test_plan\x18\x02 \x01(\x0b\x32\x1f.chromiumos.test.api.HWTestPlanH\x00\x42\x06\n\x04spec\"\xe7\x01\n\x07Request\x12,\n\x0f\x62uild_directory\x18\x01 \x01(\x0b\x32\x13.chromiumos.GcsPath\x12.\n\ntest_specs\x18\x02 \x03(\x0b\x32\x1a.test_platform.v2.TestSpec\x12G\n\x12scheduler_settings\x18\x03 \x01(\x0b\x32+.test_platform.v2.Request.SchedulerSettings\x1a\x35\n\x11SchedulerSettings\x12\x0c\n\x04pool\x18\x01 \x01(\t\x12\x12\n\nqs_account\x18\x02 \x01(\tB<Z:go.chromium.org/chromiumos/infra/proto/go/test_platform/v2b\x06proto3'
+  serialized_options=b'ZHgo.chromium.org/chromiumos/infra/proto/go/test_platform/v2;test_platform',
+  serialized_pb=b'\n\x1etest_platform/v2/request.proto\x12\x10test_platform.v2\x1a\x17\x63hromiumos/common.proto\x1a!chromiumos/test/api/v1/plan.proto\"\x7f\n\x08TestSpec\x12,\n\x0f\x62uild_directory\x18\x01 \x01(\x0b\x32\x13.chromiumos.GcsPath\x12=\n\x0fhw_test_plan_v1\x18\x02 \x01(\x0b\x32\".chromiumos.test.api.v1.HWTestPlanH\x00\x42\x06\n\x04spec\"\xe7\x01\n\x07Request\x12,\n\x0f\x62uild_directory\x18\x01 \x01(\x0b\x32\x13.chromiumos.GcsPath\x12.\n\ntest_specs\x18\x02 \x03(\x0b\x32\x1a.test_platform.v2.TestSpec\x12G\n\x12scheduler_settings\x18\x03 \x01(\x0b\x32+.test_platform.v2.Request.SchedulerSettings\x1a\x35\n\x11SchedulerSettings\x12\x0c\n\x04pool\x18\x01 \x01(\t\x12\x12\n\nqs_account\x18\x02 \x01(\tBJZHgo.chromium.org/chromiumos/infra/proto/go/test_platform/v2;test_platformb\x06proto3'
   ,
-  dependencies=[chromiumos_dot_common__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_coverage__rule__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_plan__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_provision__state__pb2.DESCRIPTOR,])
+  dependencies=[chromiumos_dot_common__pb2.DESCRIPTOR,chromiumos_dot_test_dot_api_dot_v1_dot_plan__pb2.DESCRIPTOR,])
 
 
 
@@ -44,7 +42,7 @@
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='hw_test_plan', full_name='test_platform.v2.TestSpec.hw_test_plan', index=1,
+      name='hw_test_plan_v1', full_name='test_platform.v2.TestSpec.hw_test_plan_v1', index=1,
       number=2, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
@@ -65,8 +63,8 @@
       name='spec', full_name='test_platform.v2.TestSpec.spec',
       index=0, containing_type=None, fields=[]),
   ],
-  serialized_start=193,
-  serialized_end=314,
+  serialized_start=112,
+  serialized_end=239,
 )
 
 
@@ -103,8 +101,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=495,
-  serialized_end=548,
+  serialized_start=420,
+  serialized_end=473,
 )
 
 _REQUEST = _descriptor.Descriptor(
@@ -147,15 +145,15 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=317,
-  serialized_end=548,
+  serialized_start=242,
+  serialized_end=473,
 )
 
 _TESTSPEC.fields_by_name['build_directory'].message_type = chromiumos_dot_common__pb2._GCSPATH
-_TESTSPEC.fields_by_name['hw_test_plan'].message_type = chromiumos_dot_test_dot_api_dot_plan__pb2._HWTESTPLAN
+_TESTSPEC.fields_by_name['hw_test_plan_v1'].message_type = chromiumos_dot_test_dot_api_dot_v1_dot_plan__pb2._HWTESTPLAN
 _TESTSPEC.oneofs_by_name['spec'].fields.append(
-  _TESTSPEC.fields_by_name['hw_test_plan'])
-_TESTSPEC.fields_by_name['hw_test_plan'].containing_oneof = _TESTSPEC.oneofs_by_name['spec']
+  _TESTSPEC.fields_by_name['hw_test_plan_v1'])
+_TESTSPEC.fields_by_name['hw_test_plan_v1'].containing_oneof = _TESTSPEC.oneofs_by_name['spec']
 _REQUEST_SCHEDULERSETTINGS.containing_type = _REQUEST
 _REQUEST.fields_by_name['build_directory'].message_type = chromiumos_dot_common__pb2._GCSPATH
 _REQUEST.fields_by_name['test_specs'].message_type = _TESTSPEC
diff --git a/api/references/build_api_proto.md b/api/references/build_api_proto.md
new file mode 100644
index 0000000..c0e1bb8
--- /dev/null
+++ b/api/references/build_api_proto.md
@@ -0,0 +1,75 @@
+# Build API Proto Reference
+
+This doc answers questions you may have about the Build API proto.
+It does not cover the proto for specific endpoints, just more general topics,
+and the overall structure.
+
+## Service and Method Options
+
+The service and method options extensions in
+[`chromite/api/build_api.proto`](https://chromium.googlesource.com/chromiumos/infra/proto/+/refs/heads/main/src/chromite/api/build_api.proto)
+define some key information about the implementation of the endpoint.
+
+### Implementation Routing
+
+The service option `module` is required for all services.
+This option defines the python module in `chromite/api/controller` where
+all the service's methods are implemented.
+Generally, the protos contain a single service, and that service will map to a
+controller module of the same name, but that is not required, and this option is
+how that is managed.
+
+The methods are each implemented as a function in the service's controller
+module.
+By default, the method's name is used to determine what function to call.
+This default behavior can be optionally overridden by setting the method's
+`implementation_name` option to the name of the function.
+
+### Chroot Assertions
+
+The `service_chroot_assert` and `method_chroot_assert` options define where the
+endpoint should run.
+The `service_chroot_assert` option defines the default for all methods in the
+service, and the `method_chroot_assert` option allows overriding the service
+default for the method.
+
+When left undefined, the endpoint will be allowed to run inside or outside the
+SDK, but in practice means the builders will always run it outside.
+`OUTSIDE` will cause the Build API to raise an error if it is being run inside
+the SDK.
+`INSIDE` will cause the Build API to automatically re-execute the endpoint
+inside the SDK when it is outside.
+There are some built-in utilities that help make working inside the chroot as
+easy as possible, see the [chroot reference](./chroot.md) for more information.
+
+### List Visibility
+
+The `service_visibility` and `method_visibility` options allow showing (default)
+or hiding whole services and specific methods in the `MethodService/Get` list.
+This is intended for cases like hiding an endpoint that's being actively
+developed.
+
+
+## Proto Structure
+
+For the most part, the proto lives in the
+[infra/proto repo](https://chromium.googlesource.com/chromiumos/infra/proto/).
+The [Build API README](../README.md) has some information about specific
+directories used by the Build API.
+
+### infra/proto vs chromite/infra/proto
+
+The `infra/proto` repo itself appears twice in the chromiumos checkout;
+`infra/proto/` and `chromite/infra/proto`.
+The `infra/proto` checkout is always at ToT.
+The `chromite/infra/proto` checkout is branched along with chromite.
+
+These two checkouts reflect the two versions of proto that would be used for the
+checkout.
+The CI recipes code will always be using ToT, while chromite has to use branched
+proto to ensure the implementation and proto match.
+Chromite also currently commits its compiled proto to ensure it has a version of
+the proto that works with its vendored protobuf library, so while it doesn't
+need the branched `chromite/infra/proto` to compile its proto, the checkout
+ensures we have a human readable version of the proto being used by chromite in
+the repository.
diff --git a/api/references/chroot.md b/api/references/chroot.md
index 91dc923..ad70e41 100644
--- a/api/references/chroot.md
+++ b/api/references/chroot.md
@@ -6,6 +6,11 @@
 walk-through of the steps to set up an endpoint that runs inside the SDK,
 and is the recommended starting point if you're just getting started.
 
+## Chroot Assert Options
+
+Where an endpoint is run is determined by the Chroot Assert Service and Method
+Options.
+See the [Build API Proto Reference](./build_api_proto.md) for more information.
 
 ## Overview: The "Path" Messages
 
diff --git a/api/router.py b/api/router.py
index afc0028..a89773b 100644
--- a/api/router.py
+++ b/api/router.py
@@ -27,6 +27,7 @@
 from chromite.api.gen.chromite.api import depgraph_pb2
 from chromite.api.gen.chromite.api import firmware_pb2
 from chromite.api.gen.chromite.api import image_pb2
+from chromite.api.gen.chromite.api import metadata_pb2
 from chromite.api.gen.chromite.api import packages_pb2
 from chromite.api.gen.chromite.api import payload_pb2
 from chromite.api.gen.chromite.api import sdk_pb2
@@ -331,6 +332,9 @@
       # Parse goma.
       chroot.goma = field_handler.handle_goma(input_msg, chroot.path)
 
+      # Parse remoteexec.
+      chroot.remoteexec = field_handler.handle_remoteexec(input_msg)
+
       # Build inside-chroot paths for the input, output, and config messages.
       new_input = os.path.join(tempdir, self.REEXEC_INPUT_FILE)
       chroot_input = '/%s' % os.path.relpath(new_input, chroot.path)
@@ -427,6 +431,7 @@
   router.Register(depgraph_pb2)
   router.Register(firmware_pb2)
   router.Register(image_pb2)
+  router.Register(metadata_pb2)
   router.Register(packages_pb2)
   router.Register(payload_pb2)
   router.Register(sdk_pb2)
diff --git a/api/validate.py b/api/validate.py
index c2ebc44..7501c0e 100644
--- a/api/validate.py
+++ b/api/validate.py
@@ -197,11 +197,11 @@
             failed.append((val, msg))
 
         if failed:
-          msg = '{}.[all] one or more values failed check "{}"\n'.format(
-              field, constraint_description)
+          msg = f'{field}.[all] one or more values failed check ' \
+                f'"{constraint_description}"\n'
 
           for value, msg in failed:
-            msg += '  {}: {}\n'.format(value, msg)
+            msg += '  %s: %s\n' % (value, msg)
           cros_build_lib.Die(msg)
 
       return func(input_proto, output_proto, config, *args, **kwargs)
diff --git a/bin/cros_check_patches b/bin/build_packages
similarity index 100%
rename from bin/cros_check_patches
rename to bin/build_packages
diff --git a/bin/cros_check_patches b/bin/cros_generate_quick_provision_payload
similarity index 100%
copy from bin/cros_check_patches
copy to bin/cros_generate_quick_provision_payload
diff --git a/bin/cros_check_patches b/bin/generate_reclient_inputs
similarity index 100%
copy from bin/cros_check_patches
copy to bin/generate_reclient_inputs
diff --git a/cbuildbot/afdo.py b/cbuildbot/afdo.py
deleted file mode 100644
index 05406be..0000000
--- a/cbuildbot/afdo.py
+++ /dev/null
@@ -1,1270 +0,0 @@
-# Copyright 2014 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Module containing the various utilities to build Chrome with AFDO.
-
-For a description of AFDO see gcc.gnu.org/wiki/AutoFDO.
-"""
-
-import collections
-import datetime
-import glob
-import json
-import logging
-import os
-import re
-from typing import TYPE_CHECKING
-
-from chromite.lib import constants
-from chromite.lib import cros_build_lib
-from chromite.lib import failures_lib
-from chromite.lib import git
-from chromite.lib import gs
-from chromite.lib import osutils
-from chromite.lib import path_util
-from chromite.lib import timeout_util
-
-if TYPE_CHECKING:
-  from chromite.lib.parser import package_info
-
-
-# AFDO-specific constants.
-AFDO_SUFFIX = '.afdo'
-COMPRESSION_SUFFIX = '.bz2'
-
-# Chrome URL where AFDO data is stored.
-_gsurls = {}
-AFDO_CHROOT_ROOT = os.path.join('%(build_root)s', constants.DEFAULT_CHROOT_DIR)
-AFDO_LOCAL_DIR = os.path.join('%(root)s', 'tmp')
-AFDO_BUILDROOT_LOCAL = AFDO_LOCAL_DIR % {'root': AFDO_CHROOT_ROOT}
-CHROME_ARCH_VERSION = '%(package)s-%(arch)s-%(version)s'
-CHROME_PERF_AFDO_FILE = '%s.perf.data' % CHROME_ARCH_VERSION
-CHROME_AFDO_FILE = '%s%s' % (CHROME_ARCH_VERSION, AFDO_SUFFIX)
-CHROME_ARCH_RELEASE = '%(package)s-%(arch)s-%(release)s'
-LATEST_CHROME_AFDO_FILE = 'latest-%s%s' % (CHROME_ARCH_RELEASE, AFDO_SUFFIX)
-CHROME_DEBUG_BIN = os.path.join('%(root)s', 'build/%(board)s/usr/lib/debug',
-                                'opt/google/chrome/chrome.debug')
-# regex to find AFDO file for specific architecture within the ebuild file.
-CHROME_EBUILD_AFDO_REGEX = (
-    r'^(?P<bef>AFDO_FILE\["%s"\]=")(?P<name>.*)(?P<aft>")')
-# and corresponding replacement string.
-CHROME_EBUILD_AFDO_REPL = r'\g<bef>%s\g<aft>'
-
-GSURL_BASE_BENCH = 'gs://chromeos-prebuilt/afdo-job/llvm'
-GSURL_BASE_CWP = 'gs://chromeos-prebuilt/afdo-job/cwp/chrome'
-GSURL_BASE_RELEASE = 'gs://chromeos-prebuilt/afdo-job/release-merged'
-GSURL_CHROME_PERF = os.path.join(GSURL_BASE_BENCH,
-                                 CHROME_PERF_AFDO_FILE + COMPRESSION_SUFFIX)
-GSURL_CHROME_AFDO = os.path.join(GSURL_BASE_BENCH,
-                                 CHROME_AFDO_FILE + COMPRESSION_SUFFIX)
-GSURL_LATEST_CHROME_AFDO = os.path.join(GSURL_BASE_BENCH,
-                                        LATEST_CHROME_AFDO_FILE)
-GSURL_CHROME_DEBUG_BIN = os.path.join(
-    GSURL_BASE_BENCH, CHROME_ARCH_VERSION + '.debug' + COMPRESSION_SUFFIX)
-
-AFDO_GENERATE_LLVM_PROF = '/usr/bin/create_llvm_prof'
-
-# An AFDO data is considered stale when BOTH of the following two metrics don't
-# meet. For example, if an AFDO data is generated 20 days ago but only 5 builds
-# away, it is considered valid.
-
-# How old can the AFDO data be? (in days).
-AFDO_ALLOWED_STALE_DAYS = 42
-
-# How old can the AFDO data be? (in difference of builds).
-AFDO_ALLOWED_STALE_BUILDS = 7
-
-# How old can the Kernel AFDO data be? (in days).
-KERNEL_ALLOWED_STALE_DAYS = 42
-
-# How old can the Kernel AFDO data be before sheriff got noticed? (in days).
-KERNEL_WARN_STALE_DAYS = 14
-
-# Set of boards that can generate the AFDO profile (can generate 'perf'
-# data with LBR events). Currently, it needs to be a device that has
-# at least 4GB of memory.
-#
-# This must be consistent with the definitions in autotest.
-AFDO_DATA_GENERATORS_LLVM = ('chell')
-
-AFDO_ALERT_RECIPIENTS = [
-    'chromeos-toolchain-sheriff@grotations.appspotmail.com'
-]
-
-KERNEL_PROFILE_URL = 'gs://chromeos-prebuilt/afdo-job/cwp/kernel/'
-KERNEL_PROFILE_LS_PATTERN = '*/*.gcov.xz'
-KERNEL_PROFILE_NAME_PATTERN = (
-    r'([0-9]+\.[0-9]+)/R([0-9]+)-([0-9]+)\.([0-9]+)-([0-9]+)\.gcov\.xz')
-KERNEL_PROFILE_MATCH_PATTERN = (
-    r'^AFDO_PROFILE_VERSION="R[0-9]+-[0-9]+\.[0-9]+-[0-9]+"$')
-KERNEL_PROFILE_WRITE_PATTERN = 'AFDO_PROFILE_VERSION="R%d-%d.%d-%d"'
-KERNEL_EBUILD_ROOT = os.path.join(
-    constants.SOURCE_ROOT, 'src/third_party/chromiumos-overlay/sys-kernel')
-
-# Kernels that we can't generate afdo anymore because of reasons like
-# too few samples etc.
-KERNEL_SKIP_AFDO_UPDATE = ['3.8', '3.14']
-
-GSURL_CWP_SUBDIR = {
-    'silvermont': '',
-    'airmont': 'airmont',
-    'broadwell': 'broadwell',
-}
-
-# Relative weights we should use when merging our 'release' profiles. The
-# counters in our benchmark/cwp profiles end up being multiplied by these
-# numbers, so they can technically be anything, but we have them sum to 100 for
-# ease of understanding.
-_RELEASE_BENCHMARK_MERGE_WEIGHT = 25
-_RELEASE_CWP_MERGE_WEIGHT = 75
-
-# Filename pattern of CWP profiles for Chrome
-CWP_CHROME_PROFILE_NAME_PATTERN = r'R%s-%s.%s-%s' + AFDO_SUFFIX + '.xz'
-
-BENCHMARK_PROFILE_NAME_RE = re.compile(
-    r"""
-       ^chromeos-chrome-amd64-
-       (\d+)\.                    # Major
-       (\d+)\.                    # Minor
-       (\d+)\.                    # Build
-       (\d+)                      # Patch
-       (?:_rc)?-r(\d+)            # Revision
-       (-merged)?\.
-       afdo(?:\.bz2)?$            # We don't care about the presence of .bz2,
-                                  # so we use the ignore-group '?:' operator.
-     """, re.VERBOSE)
-
-BenchmarkProfileVersion = collections.namedtuple(
-    'BenchmarkProfileVersion',
-    ['major', 'minor', 'build', 'patch', 'revision', 'is_merged'])
-
-
-class MissingAFDOData(failures_lib.StepFailure):
-  """Exception thrown when necessary AFDO data is missing."""
-
-
-class MissingAFDOMarkers(failures_lib.StepFailure):
-  """Exception thrown when necessary ebuild markers for AFDO are missing."""
-
-
-class UnknownKernelVersion(failures_lib.StepFailure):
-  """Exception thrown when the Kernel version can't be inferred."""
-
-
-class NoValidProfileFound(failures_lib.StepFailure):
-  """Exception thrown when there is no valid profile found."""
-
-
-def CompressAFDOFile(to_compress, buildroot):
-  """Compress file used by AFDO process.
-
-  Args:
-    to_compress: File to compress.
-    buildroot: buildroot where to store the compressed data.
-
-  Returns:
-    Name of the compressed data file.
-  """
-  local_dir = AFDO_BUILDROOT_LOCAL % {'build_root': buildroot}
-  dest = (os.path.join(local_dir, os.path.basename(to_compress)) +
-          COMPRESSION_SUFFIX)
-  cros_build_lib.CompressFile(to_compress, dest)
-  return dest
-
-
-def UncompressAFDOFile(to_decompress, buildroot):
-  """Decompress file used by AFDO process.
-
-  Args:
-    to_decompress: File to decompress.
-    buildroot: buildroot where to store the decompressed data.
-  """
-  local_dir = AFDO_BUILDROOT_LOCAL % {'build_root': buildroot}
-  basename = os.path.basename(to_decompress)
-  dest_basename = basename.rsplit('.', 1)[0]
-  dest = os.path.join(local_dir, dest_basename)
-  cros_build_lib.UncompressFile(to_decompress, dest)
-  return dest
-
-
-def GSUploadIfNotPresent(gs_context, src, dest):
-  """Upload a file to GS only if the file does not exist.
-
-  Will not generate an error if the file already exist in GS. It will
-  only emit a warning.
-
-  I could use GSContext.Copy(src,dest,version=0) here but it does not seem
-  to work for large files. Using GSContext.Exists(dest) instead. See
-  crbug.com/395858.
-
-  Args:
-    gs_context: GS context instance.
-    src: File to copy.
-    dest: Destination location.
-
-  Returns:
-    True if file was uploaded. False otherwise.
-  """
-  if gs_context.Exists(dest):
-    logging.warning('File %s already in GS', dest)
-    return False
-  else:
-    gs_context.Copy(src, dest, acl='public-read')
-    return True
-
-
-def GetAFDOPerfDataURL(chrome_pkg: 'package_info.PackageInfo', arch):
-  """Return the location URL for the AFDO per data file.
-
-  Build the URL for the 'perf' data file given the release and architecture.
-
-  Args:
-    chrome_pkg: Chrome package information.
-    arch: architecture we're going to build Chrome for.
-
-  Returns:
-    URL of the location of the 'perf' data file.
-  """
-
-  # The file name of the perf data is based only in the chrome version.
-  # The test case that produces it does not know anything about the
-  # revision number.
-  # TODO(llozano): perf data filename should include the revision number.
-  chrome_spec = {
-      'package': chrome_pkg.package,
-      'arch': arch,
-      'version': chrome_pkg.version,
-  }
-  return GSURL_CHROME_PERF % chrome_spec
-
-
-def CheckAFDOPerfData(chrome_pkg: 'package_info.PackageInfo', arch, gs_context):
-  """Check whether AFDO perf data exists for the given architecture.
-
-  Check if 'perf' data file for this architecture and release is available
-  in GS.
-
-  Args:
-    chrome_pkg: Chrome package information.
-    arch: architecture we're going to build Chrome for.
-    gs_context: GS context to retrieve data.
-
-  Returns:
-    True if AFDO perf data is available. False otherwise.
-  """
-  url = GetAFDOPerfDataURL(chrome_pkg, arch)
-  if not gs_context.Exists(url):
-    logging.info('Could not find AFDO perf data at %s', url)
-    return False
-
-  logging.info('Found AFDO perf data at %s', url)
-  return True
-
-
-def WaitForAFDOPerfData(chrome_pkg: 'package_info.PackageInfo',
-                        arch,
-                        buildroot,
-                        gs_context,
-                        timeout=constants.AFDO_GENERATE_TIMEOUT):
-  """Wait for AFDO perf data to show up (with an appropriate timeout).
-
-  Wait for AFDO 'perf' data to show up in GS and copy it into a temp
-  directory in the buildroot.
-
-  Args:
-    arch: architecture we're going to build Chrome for.
-    chrome_pkg: Chrome package information.
-    buildroot: buildroot where AFDO data should be stored.
-    gs_context: GS context to retrieve data.
-    timeout: How long to wait total, in seconds.
-
-  Returns:
-    True if found the AFDO perf data before the timeout expired.
-    False otherwise.
-  """
-  try:
-    timeout_util.WaitForReturnTrue(
-        CheckAFDOPerfData,
-        func_args=(chrome_pkg, arch, gs_context),
-        timeout=timeout,
-        period=constants.SLEEP_TIMEOUT)
-  except timeout_util.TimeoutError:
-    logging.info('Could not find AFDO perf data before timeout')
-    return False
-
-  url = GetAFDOPerfDataURL(chrome_pkg, arch)
-  dest_dir = AFDO_BUILDROOT_LOCAL % {'build_root': buildroot}
-  dest_path = os.path.join(dest_dir, url.rsplit('/', 1)[1])
-  gs_context.Copy(url, dest_path)
-
-  UncompressAFDOFile(dest_path, buildroot)
-  logging.info('Retrieved AFDO perf data to %s', dest_path)
-  return True
-
-
-def _BuildrootToWorkDirs(buildroot):
-  chroot_root = AFDO_CHROOT_ROOT % {'build_root': buildroot}
-  local_dir = AFDO_LOCAL_DIR % {'root': chroot_root}
-  in_chroot_local_dir = AFDO_LOCAL_DIR % {'root': ''}
-  return chroot_root, local_dir, in_chroot_local_dir
-
-
-def _EnumerateMostRecentProfiles(gs_context, milestones, glob_url,
-                                 parse_profile_name):
-  """Enumerates the most recent AFDO profiles for the given Chrome releases.
-
-  Args:
-    gs_context: How we talk to gs://
-    milestones: A list of ints; each one is a major Chrome version. We'll
-      try to get the most recent profile for each of these.
-    glob_url: A URL to query gsutil with.
-    parse_profile_name: A callable that transforms a profile's filename into
-      an object that:
-      - is orderable such that |a < b| implies that |a| is an older profile
-        than |b|
-      - has a |major| attribute that indicates Chrome's major version number
-
-      Alternatively, if it returns None, we skip the given profile.
-
-  Returns:
-    A dict of {milestone_number: latest_profile_gs_url}. The keys in this
-    milestone are a (not-strict) subset of the values in |milestones|.
-  """
-  profile_listing = gs_context.List(glob_url)
-  if not profile_listing:
-    raise ValueError('No profiles matched %s' % glob_url)
-
-  parsed_profiles = []
-  for profile in profile_listing:
-    url = profile.url
-    parsed = parse_profile_name(os.path.basename(url))
-    if parsed is not None:
-      parsed_profiles.append((parsed, url))
-
-  newest = {}
-  for version in milestones:
-    profiles = [(v, url) for v, url in parsed_profiles if v.major == version]
-    if not profiles:
-      continue
-
-    _, url = max(profiles)
-    newest[version] = url
-
-  return newest
-
-
-def _EnumerateMostRecentCWPProfiles(gs_context, milestones):
-  """Enumerates the most recent CWP AFDO profiles for Chrome releases.
-
-  See _EnumerateMostRecentProfiles for info about args/return value.
-  """
-  profile_suffix = AFDO_SUFFIX + '.xz'
-  glob_url = os.path.join(GSURL_BASE_CWP, '*' + profile_suffix)
-
-  # e.g. R75-3729.38-1554716539.afdo.xz
-  profile_name_re = re.compile(
-      r"""
-         ^R(\d+)-      # Major
-         (\d+)\.       # Build
-         (\d+)-        # Patch
-         (\d+)         # Clock; breaks ties sometimes.
-         \.afdo\.xz$
-       """, re.VERBOSE)
-
-  ProfileVersion = collections.namedtuple('ProfileVersion',
-                                          ['major', 'build', 'patch', 'clock'])
-
-  def parse_profile_name(url_basename):
-    match = profile_name_re.match(url_basename)
-    if not match:
-      raise ValueError('Unparseable CWP profile name: %s' % url_basename)
-    return ProfileVersion(*[int(x) for x in match.groups()])
-
-  return _EnumerateMostRecentProfiles(gs_context, milestones, glob_url,
-                                      parse_profile_name)
-
-
-def _ParseBenchmarkProfileName(profile_name):
-  match = BENCHMARK_PROFILE_NAME_RE.match(profile_name)
-  if not match:
-    raise ValueError('Unparseable benchmark profile name: %s' % profile_name)
-
-  groups = match.groups()
-  version_groups = groups[:-1]
-  is_merged = groups[-1]
-  return BenchmarkProfileVersion(
-      *[int(x) for x in version_groups], is_merged=bool(is_merged))
-
-
-def _EnumerateMostRecentBenchmarkProfiles(gs_context, milestones):
-  """Enumerates the most recent benchmark AFDO profiles for Chrome releases.
-
-  See _EnumerateMostRecentProfiles for info about args/return value.
-  """
-  profile_suffix = AFDO_SUFFIX + COMPRESSION_SUFFIX
-  glob_url = os.path.join(GSURL_BASE_BENCH, '*' + profile_suffix)
-
-  def parse_profile_name(url_basename):
-    parsed = _ParseBenchmarkProfileName(url_basename)
-    # We don't want to merge a merged profile; merged profiles are primarily
-    # for stability, and we have CWP to provide us that.
-    return None if parsed.is_merged else parsed
-
-  return _EnumerateMostRecentProfiles(gs_context, milestones, glob_url,
-                                      parse_profile_name)
-
-
-def GenerateReleaseProfileMergePlan(gs_context, milestones):
-  """Generates a plan to merge release profiles for Chrome milestones.
-
-  Args:
-    gs_context: How we talk to gs://
-    milestones: A list of ints; Chrome milestones
-
-  Returns:
-    A tuple (a, b), where:
-      - |b| is a dict of {milestone: (cwp_profile, benchmark_profile)}, where
-        |benchmark_profile| and |cwp_profile| are paths in gs:// that point to
-        the most recent benchmark and CWP profiles for |milestone|.
-      - |a| is a sorted list of milestones that aren't present in |b|, but are
-        present in |milestones|.
-  """
-  benchmark_profiles = _EnumerateMostRecentBenchmarkProfiles(
-      gs_context, milestones)
-  cwp_profiles = _EnumerateMostRecentCWPProfiles(gs_context, milestones)
-
-  planned_merges = {
-      version: (cwp_profiles[version], benchmark_profile)
-      for version, benchmark_profile in benchmark_profiles.items()
-      if version in cwp_profiles
-  }
-  skipped = sorted(set(milestones) - set(planned_merges))
-  return skipped, planned_merges
-
-
-def ExecuteReleaseProfileMergePlan(gs_context, buildroot, merge_plan):
-  """Generates release profiles, given a release profile merge plan.
-
-  Args:
-    gs_context: How we talk to gs://
-    buildroot: Our buildroot
-    merge_plan: The second result of GenerateReleaseProfileMergePlan. This
-      determines the profiles we pull and merge.
-  """
-  _, work_dir, chroot_work_dir = _BuildrootToWorkDirs(buildroot)
-
-  def path_pair(suffix):
-    outside_chroot = os.path.join(work_dir, suffix)
-    in_chroot = os.path.join(chroot_work_dir, suffix)
-    return in_chroot, outside_chroot
-
-  chroot_work_dir, work_dir = path_pair('afdo_data_merge')
-
-  def copy_profile(gs_path, local_path):
-    assert local_path.endswith('.afdo'), local_path
-    assert not gs_path.endswith('.afdo'), gs_path
-
-    compression_suffix = os.path.splitext(gs_path)[1]
-    temp_path = local_path + compression_suffix
-    gs_context.Copy(gs_path, temp_path)
-    cros_build_lib.UncompressFile(temp_path, local_path)
-
-  merge_results = {}
-  for version, (cwp_profile, benchmark_profile) in merge_plan.items():
-    chroot_benchmark_path, benchmark_path = path_pair('benchmark.afdo')
-    copy_profile(benchmark_profile, benchmark_path)
-
-    chroot_cwp_path, cwp_path = path_pair('cwp.afdo')
-    copy_profile(cwp_profile, cwp_path)
-
-    chroot_merged_path, merged_path = path_pair('m%d.afdo' % version)
-    merge_weights = [
-        (chroot_cwp_path, _RELEASE_CWP_MERGE_WEIGHT),
-        (chroot_benchmark_path, _RELEASE_BENCHMARK_MERGE_WEIGHT),
-    ]
-    _MergeAFDOProfiles(merge_weights, chroot_merged_path, use_compbinary=True)
-
-    comp_merged_path = merged_path + COMPRESSION_SUFFIX
-    cros_build_lib.CompressFile(merged_path, comp_merged_path)
-    merge_results[version] = comp_merged_path
-
-  return merge_results
-
-
-def UploadReleaseProfiles(gs_context, run_id, merge_plan, merge_results):
-  """Uploads the profiles in merge_results to our release profile bucket.
-
-  Args:
-    gs_context: Our GS context
-    run_id: A unique identifier for this run. Generally recommended to be the
-      number of seconds since the unix epoch, or something similarly difficult
-      to 'collide' with other runs. This is used in paths to guarantee
-      uniqueness.
-    merge_plan: The merge plan that generated the given |merge_results|. Only
-      used to write to a metadata file, so we know what went into this profile.
-    merge_results: A map describing the profiles to upload; you can get one
-      from ExecuteReleaseProfileMergePlan.
-  """
-  gs_url_base = os.path.join(GSURL_BASE_RELEASE, run_id)
-
-  def copy_file_to_gs(local_path, remote_path):
-    # Note that version=0 implies that we'll never overwrite anything. If
-    # run_id is truly unique, this should never make a difference.
-    gs_context.Copy(local_path, remote_path, acl='public-read', version=0)
-
-  for version, profile in merge_results.items():
-    suffix = os.path.splitext(profile)[1]
-    assert suffix != '.afdo', 'All profiles should be compressed.'
-    output_path = os.path.join(gs_url_base,
-                               'profiles/m%d.afdo%s' % (version, suffix))
-    copy_file_to_gs(profile, output_path)
-
-  # Write a map describing the profiles that have been uploaded. Not
-  # compressed, because it's expected to be <500 bytes. At the time of writing,
-  # no automated system relies on these; we just write them so it's easier to
-  # understand what 'gs://path/to/profiles/m75.afdo' actually consists of.
-  temp_dir = osutils.GetGlobalTempDir()
-  meta_file_path = os.path.join(temp_dir, 'meta.json')
-  osutils.WriteFile(meta_file_path, json.dumps(merge_plan))
-  copy_file_to_gs(meta_file_path, os.path.join(gs_url_base, 'meta.json'))
-
-
-def _MergeAFDOProfiles(chroot_profile_list,
-                       chroot_output_profile,
-                       use_compbinary=False):
-  """Merges the given profile list.
-
-  Args:
-    chroot_profile_list: a list of (profile_path, profile_weight).
-      Profile_weight is an int that tells us how to weight the profile compared
-      to everything else.
-    chroot_output_profile: where to store the result profile.
-    use_compbinary: whether to use the new compressed binary AFDO profile
-      format.
-  """
-  if not chroot_profile_list:
-    raise ValueError('Need profiles to merge')
-
-  # A regular llvm-profdata command looks like:
-  # llvm-profdata merge [-sample] -output=/path/to/output input1 [input2
-  #                                                               [input3 ...]]
-  #
-  # Alternatively, we can specify inputs by `-weighted-input=A,file`, where A
-  # is a multiplier of the sample counts in the profile.
-  merge_command = [
-      'llvm-profdata',
-      'merge',
-      '-sample',
-      '-output=' + chroot_output_profile,
-  ]
-
-  merge_command += [
-      '-weighted-input=%d,%s' % (weight, name)
-      for name, weight in chroot_profile_list
-  ]
-
-  if use_compbinary:
-    merge_command.append('-compbinary')
-
-  cros_build_lib.run(
-      merge_command, enter_chroot=True, capture_output=True, print_cmd=True)
-
-
-def _RemoveIndirectCallTargetsFromProfile(chroot_input_path,
-                                          chroot_output_path):
-  """Removes indirect call targets from the given profile.
-
-  Args:
-    chroot_input_path: the profile in the chroot to remove indirect call
-      targets from.
-    chroot_output_path: where to drop the new profile. May be the same name as
-      chroot_input_path.
-  """
-
-  removal_script = ('/mnt/host/source/src/third_party/toolchain-utils/'
-                    'afdo_redaction/remove_indirect_calls.py')
-
-  def UniqueChrootFilePath(path):
-    # If this fires, we can do stuff with tempfile. I don't think it
-    # will, and I like path names without a lot of garbage in them.
-    if os.path.exists(path_util.FromChrootPath(path)):
-      raise ValueError('Path %r already exists; refusing to overwrite.' % path)
-    return path
-
-  input_as_txt = UniqueChrootFilePath(chroot_input_path + '.txt')
-
-  # This is mostly here because yapf has ugly formatting when we do
-  # foo(['a long list that', 'wraps on multiple', 'lines'], kwarg=1, kwarg=2)
-  def RunCommand(cmd):
-    cros_build_lib.run(cmd, enter_chroot=True, print_cmd=True)
-
-  RunCommand([
-      'llvm-profdata',
-      'merge',
-      '-sample',
-      '-output=' + input_as_txt,
-      '-text',
-      chroot_input_path,
-  ])
-
-  output_as_txt = UniqueChrootFilePath(chroot_output_path + '.txt')
-  RunCommand([
-      removal_script,
-      '--input=' + input_as_txt,
-      '--output=' + output_as_txt,
-  ])
-
-  # FIXME: Maybe want to use compbinary here.
-  RunCommand([
-      'llvm-profdata',
-      'merge',
-      '-sample',
-      '-output=' + chroot_output_path,
-      output_as_txt,
-  ])
-
-
-def _CompressAndUploadAFDOProfileIfNotPresent(gs_context, buildroot, gsurl_base,
-                                              profile_to_upload_path):
-  """Compresses and potentially uploads the given profile."""
-  compressed_path = CompressAFDOFile(profile_to_upload_path, buildroot)
-  compressed_basename = os.path.basename(compressed_path)
-  gs_target = os.path.join(gsurl_base, compressed_basename)
-  uploaded = GSUploadIfNotPresent(gs_context, compressed_path, gs_target)
-  return uploaded
-
-
-def CreateAndUploadMergedAFDOProfile(gs_context,
-                                     buildroot,
-                                     unmerged_name,
-                                     recent_to_merge=5,
-                                     max_age_days=14):
-  """Create a merged AFDO profile from recent AFDO profiles and upload it.
-
-  If the upload would overwrite an existing merged file, this skips the upload.
-
-  Args:
-    gs_context: GS Context
-    buildroot: The build root
-    unmerged_name: name of the AFDO profile we've just uploaded. No profiles
-      whose names are lexicographically ordered after this are candidates for
-      selection.
-    recent_to_merge: The maximum number of profiles to merge
-    max_age_days: Don't merge profiles older than max_age_days days old.
-
-  Returns:
-    A (str, bool) of:
-      - The name of a merged profile in GSURL_BASE_BENCH if the AFDO profile is
-        a candidate for merging. Otherwise, None.
-      - Whether we uploaded a merged profile.
-  """
-  _, work_dir, chroot_work_dir = _BuildrootToWorkDirs(buildroot)
-  profile_suffix = AFDO_SUFFIX + COMPRESSION_SUFFIX
-  merged_suffix = '-merged'
-
-  glob_url = os.path.join(GSURL_BASE_BENCH, '*' + profile_suffix)
-  benchmark_listing = gs_context.List(glob_url, details=True)
-
-  unmerged_version = _ParseBenchmarkProfileName(unmerged_name)
-
-  def get_ordered_mergeable_profiles(benchmark_listing):
-    """Returns a list of mergeable profiles ordered by increasing version."""
-    profile_versions = [(_ParseBenchmarkProfileName(os.path.basename(x.url)), x)
-                        for x in benchmark_listing]
-    # Exclude merged profiles, because merging merged profiles into merged
-    # profiles is likely bad.
-    candidates = [(version, x)
-                  for version, x in profile_versions
-                  if unmerged_version >= version and not version.is_merged]
-    candidates.sort()
-    return [x for _, x in candidates]
-
-  benchmark_profiles = get_ordered_mergeable_profiles(benchmark_listing)
-  if not benchmark_profiles:
-    logging.warning('Skipping merged profile creation: no merge candidates '
-                    'found')
-    return None, False
-
-  base_time = benchmark_profiles[-1].creation_time
-  time_cutoff = base_time - datetime.timedelta(days=max_age_days)
-  merge_candidates = [
-      p for p in benchmark_profiles if p.creation_time >= time_cutoff
-  ]
-
-  merge_candidates = merge_candidates[-recent_to_merge:]
-
-  # This should never happen, but be sure we're not merging a profile into
-  # itself anyway. It's really easy for that to silently slip through, and can
-  # lead to overrepresentation of a single profile, which just causes more
-  # noise.
-  assert len(set(p.url for p in merge_candidates)) == len(merge_candidates)
-
-  # Merging a profile into itself is pointless.
-  if len(merge_candidates) == 1:
-    logging.warning('Skipping merged profile creation: we only have a single '
-                    'merge candidate.')
-    return None, False
-
-  chroot_afdo_files = []
-  for candidate in merge_candidates:
-    # It would be slightly less complex to just name these off as
-    # profile-1.afdo, profile-2.afdo, ... but the logs are more readable if we
-    # keep the basename from gs://.
-    candidate_name = os.path.basename(candidate.url)
-    candidate_uncompressed_name = candidate_name[:-len(COMPRESSION_SUFFIX)]
-
-    copy_from = candidate.url
-    copy_to = os.path.join(work_dir, candidate_name)
-    copy_to_uncompressed = os.path.join(work_dir, candidate_uncompressed_name)
-    chroot_file = os.path.join(chroot_work_dir, candidate_uncompressed_name)
-
-    gs_context.Copy(copy_from, copy_to)
-    cros_build_lib.UncompressFile(copy_to, copy_to_uncompressed)
-    chroot_afdo_files.append(chroot_file)
-
-  afdo_basename = os.path.basename(chroot_afdo_files[-1])
-  assert afdo_basename.endswith(AFDO_SUFFIX)
-  afdo_basename = afdo_basename[:-len(AFDO_SUFFIX)]
-
-  raw_merged_basename = 'raw-' + afdo_basename + merged_suffix + AFDO_SUFFIX
-  chroot_raw_merged_output_path = os.path.join(chroot_work_dir,
-                                               raw_merged_basename)
-
-  # Weight all profiles equally.
-  _MergeAFDOProfiles([(profile, 1) for profile in chroot_afdo_files],
-                     chroot_raw_merged_output_path)
-
-  profile_to_upload_basename = afdo_basename + merged_suffix + AFDO_SUFFIX
-  profile_to_upload_path = os.path.join(work_dir, profile_to_upload_basename)
-  chroot_profile_to_upload_path = os.path.join(chroot_work_dir,
-                                               profile_to_upload_basename)
-
-  _RemoveIndirectCallTargetsFromProfile(chroot_raw_merged_output_path,
-                                        chroot_profile_to_upload_path)
-
-  result_basename = os.path.basename(profile_to_upload_path)
-  return result_basename, _CompressAndUploadAFDOProfileIfNotPresent(
-      gs_context, buildroot, GSURL_BASE_BENCH, profile_to_upload_path)
-
-
-def PatchChromeEbuildAFDOFile(ebuild_file, profiles):
-  """Patch the Chrome ebuild with the dictionary of {arch: afdo_file} pairs.
-
-  Args:
-    ebuild_file: path of the ebuild file within the chroot.
-    profiles: {source: afdo_file} pairs to put into the ebuild.
-  """
-  original_ebuild = path_util.FromChrootPath(ebuild_file)
-  modified_ebuild = '%s.new' % original_ebuild
-
-  patterns = {}
-  repls = {}
-  markers = {}
-  for source in profiles.keys():
-    patterns[source] = re.compile(CHROME_EBUILD_AFDO_REGEX % source)
-    repls[source] = CHROME_EBUILD_AFDO_REPL % profiles[source]
-    markers[source] = False
-
-  with open(original_ebuild, 'r') as original:
-    with open(modified_ebuild, 'w') as modified:
-      for line in original:
-        for source in profiles.keys():
-          matched = patterns[source].match(line)
-          if matched:
-            markers[source] = True
-            modified.write(patterns[source].sub(repls[source], line))
-            break
-        else:  # line without markers, just copy it.
-          modified.write(line)
-
-  for source, found in markers.items():
-    if not found:
-      raise MissingAFDOMarkers('Chrome ebuild file does not have appropriate '
-                               'AFDO markers for source %s' % source)
-
-  os.rename(modified_ebuild, original_ebuild)
-
-
-def UpdateManifest(ebuild_file, ebuild_prog='ebuild'):
-  """Regenerate the Manifest file.
-
-  Args:
-    ebuild_file: path to the ebuild file
-    ebuild_prog: the ebuild command; can be board specific
-  """
-  gen_manifest_cmd = [ebuild_prog, ebuild_file, 'manifest', '--force']
-  cros_build_lib.run(gen_manifest_cmd, enter_chroot=True, print_cmd=True)
-
-
-def CommitIfChanged(ebuild_dir, message):
-  """If there are changes to ebuild or Manifest, commit them.
-
-  Args:
-    ebuild_dir: the path to the directory of ebuild in the chroot
-    message: commit message
-  """
-  # Check if anything changed compared to the previous version.
-  modifications = git.RunGit(
-      ebuild_dir, ['status', '--porcelain', '-uno'],
-      capture_output=True,
-      print_cmd=True).output
-  if not modifications:
-    logging.info('AFDO info for the ebuilds did not change. '
-                 'Nothing to commit')
-    return
-
-  git.RunGit(ebuild_dir, ['commit', '-a', '-m', message], print_cmd=True)
-
-
-def UpdateChromeEbuildAFDOFile(board, profiles):
-  """Update chrome ebuild with the dictionary of {arch: afdo_file} pairs.
-
-  Modifies the Chrome ebuild to set the appropriate AFDO file for each
-  given architecture. Regenerates the associated Manifest file and
-  commits the new ebuild and Manifest.
-
-  Args:
-    board: board we are building Chrome for.
-    profiles: {arch: afdo_file} pairs to put into the ebuild.
-              These are profiles from selected benchmarks.
-  """
-  # Find the Chrome ebuild file.
-  equery_prog = 'equery'
-  ebuild_prog = 'ebuild'
-  if board:
-    equery_prog += '-%s' % board
-    ebuild_prog += '-%s' % board
-
-  equery_cmd = [equery_prog, 'w', 'chromeos-chrome']
-  ebuild_file = cros_build_lib.run(
-      equery_cmd, enter_chroot=True, stdout=True).output.rstrip()
-
-  # Patch the ebuild file with the names of the available afdo_files.
-  PatchChromeEbuildAFDOFile(ebuild_file, profiles)
-
-  # Also patch the 9999 ebuild. This is necessary because the uprev
-  # process starts from the 9999 ebuild file and then compares to the
-  # current version to see if the uprev is really necessary. We dont
-  # want the names of the available afdo_files to show as differences.
-  # It also allows developers to do USE=afdo_use when using the 9999
-  # ebuild.
-  ebuild_9999 = os.path.join(
-      os.path.dirname(ebuild_file), 'chromeos-chrome-9999.ebuild')
-  PatchChromeEbuildAFDOFile(ebuild_9999, profiles)
-
-  UpdateManifest(ebuild_9999, ebuild_prog)
-
-  ebuild_dir = path_util.FromChrootPath(os.path.dirname(ebuild_file))
-  CommitIfChanged(ebuild_dir, 'Update profiles and manifests for Chrome.')
-
-
-def VerifyLatestAFDOFile(afdo_release_spec, buildroot, gs_context):
-  """Verify that the latest AFDO profile for a release is suitable.
-
-  Find the latest AFDO profile file for a particular release and check
-  that it is not too stale. The latest AFDO profile name for a release
-  can be found in a file in GS under the name
-  latest-chrome-<arch>-<release>.afdo.
-
-  Args:
-    afdo_release_spec: architecture and release to find the latest AFDO
-        profile for.
-    buildroot: buildroot where AFDO data should be stored.
-    gs_context: GS context to retrieve data.
-
-  Returns:
-    The first return value is the name of the AFDO profile file found. None
-    otherwise.
-    The second return value indicates whether the profile found is expired or
-    not. False when no profile is found.
-  """
-  latest_afdo_url = GSURL_LATEST_CHROME_AFDO % afdo_release_spec
-
-  # Check if latest-chrome-<arch>-<release>.afdo exists.
-  try:
-    latest_detail = gs_context.List(latest_afdo_url, details=True)
-  except gs.GSNoSuchKey:
-    logging.info('Could not find latest AFDO info file %s', latest_afdo_url)
-    return None, False
-
-  # Then get the name of the latest valid AFDO profile file.
-  local_dir = AFDO_BUILDROOT_LOCAL % {'build_root': buildroot}
-  latest_afdo_file = LATEST_CHROME_AFDO_FILE % afdo_release_spec
-  latest_afdo_path = os.path.join(local_dir, latest_afdo_file)
-  gs_context.Copy(latest_afdo_url, latest_afdo_path)
-
-  cand = osutils.ReadFile(latest_afdo_path).strip()
-  cand_build = int(cand.split('.')[2])
-  curr_build = int(afdo_release_spec['build'])
-
-  # Verify the AFDO profile file is not too stale.
-  mod_date = latest_detail[0].creation_time
-  curr_date = datetime.datetime.now()
-  allowed_stale_days = datetime.timedelta(days=AFDO_ALLOWED_STALE_DAYS)
-  if ((curr_date - mod_date) > allowed_stale_days and
-      (curr_build - cand_build) > AFDO_ALLOWED_STALE_BUILDS):
-    logging.info('Found latest AFDO info file %s but it is too old',
-                 latest_afdo_url)
-    return cand, True
-
-  return cand, False
-
-
-def GetBenchmarkProfile(chrome_pkg: 'package_info.PackageInfo', _source,
-                        buildroot, gs_context):
-  """Try to find the latest suitable AFDO profile file.
-
-  Try to find the latest AFDO profile generated for current release
-  and architecture. If there is none, check the previous release (mostly
-  in case we have just branched).
-
-  Args:
-    chrome_pkg: Chrome package information.
-    _source: benchmark source for which we are looking
-    buildroot: buildroot where AFDO data should be stored.
-    gs_context: GS context to retrieve data.
-
-  Returns:
-    Name of latest suitable AFDO profile file if one is found.
-    None otherwise.
-  """
-
-  # Currently, benchmark based profiles can only be generated on amd64.
-  arch = 'amd64'
-  version_numbers = chrome_pkg.vr.split('.')
-  current_release = version_numbers[0]
-  current_build = version_numbers[2]
-  afdo_release_spec = {
-      'package': chrome_pkg.package,
-      'arch': arch,
-      'release': current_release,
-      'build': current_build
-  }
-  afdo_file, expired = VerifyLatestAFDOFile(afdo_release_spec, buildroot,
-                                            gs_context)
-  if afdo_file and not expired:
-    return afdo_file
-
-  # The profile found in current release is too old. This clearly is a sign of
-  # problem. Therefore, don't try to find another one in previous branch.
-  if expired:
-    return None
-
-  # Could not find suitable AFDO file for the current release.
-  # Let's see if there is one from the previous release.
-  previous_release = str(int(current_release) - 1)
-  prev_release_spec = {
-      'package': chrome_pkg.package,
-      'arch': arch,
-      'release': previous_release,
-      'build': current_build
-  }
-  afdo_file, expired = VerifyLatestAFDOFile(prev_release_spec, buildroot,
-                                            gs_context)
-  if expired:
-    return None
-  return afdo_file
-
-
-def UpdateLatestAFDOProfileInGS(chrome_pkg: 'package_info.PackageInfo', arch,
-                                buildroot, profile_name, gs_context):
-  """Updates our 'latest profile' file in GS to point to `profile_name`.
-
-  Args:
-    chrome_pkg: Chrome package information.
-    arch: architecture for which we are looking for AFDO profile.
-    buildroot: buildroot where AFDO data should be stored.
-    profile_name: Name of the profile to point the 'latest profile' file at.
-    gs_context: GS context.
-  """
-  _, local_dir, _ = _BuildrootToWorkDirs(buildroot)
-
-  # Create latest-chrome-<arch>-<release>.afdo pointing to the name
-  # of the AFDO profile file and upload to GS.
-  current_release = chrome_pkg.vr.split('.')[0]
-  afdo_release_spec = {
-      'package': chrome_pkg.package,
-      'arch': arch,
-      'release': current_release
-  }
-  latest_afdo_file = LATEST_CHROME_AFDO_FILE % afdo_release_spec
-  latest_afdo_path = os.path.join(local_dir, latest_afdo_file)
-  osutils.WriteFile(latest_afdo_path, profile_name)
-  gs_context.Copy(
-      latest_afdo_path,
-      GSURL_LATEST_CHROME_AFDO % afdo_release_spec,
-      acl='public-read')
-
-
-def GenerateAFDOData(chrome_pkg: 'package_info.PackageInfo', arch, board,
-                     buildroot, gs_context):
-  """Generate AFDO profile data from 'perf' data.
-
-  Given the 'perf' profile, generate an AFDO profile using create_llvm_prof.
-  It also creates a latest-chrome-<arch>-<release>.afdo file pointing
-  to the generated AFDO profile.
-  Uploads the generated data to GS for retrieval by the chrome ebuild
-  file when doing an 'afdo_use' build.
-  It is possible the generated data has previously been uploaded to GS
-  in which case this routine will not upload the data again. Uploading
-  again may cause verication failures for the ebuild file referencing
-  the previous contents of the data.
-
-  Args:
-    chrome_pkg: Chrome package information.
-    arch: architecture for which we are looking for AFDO profile.
-    board: board we are building for.
-    buildroot: buildroot where AFDO data should be stored.
-    gs_context: GS context to retrieve/store data.
-
-  Returns:
-    Name of the AFDO profile file generated if successful, and whether or not
-    it was uploaded.
-  """
-  CHROME_UNSTRIPPED_NAME = 'chrome.unstripped'
-
-  afdo_spec = {
-      'package': chrome_pkg.package,
-      'arch': arch,
-      'version': chrome_pkg.vr,
-  }
-  chroot_root, local_dir, in_chroot_local_dir = _BuildrootToWorkDirs(buildroot)
-
-  # Upload compressed chrome debug binary to GS for triaging purposes.
-  # TODO(llozano): This simplifies things in case of need of triaging
-  # problems but is it really necessary?
-  debug_bin = CHROME_DEBUG_BIN % {'root': chroot_root, 'board': board}
-  comp_debug_bin_path = CompressAFDOFile(debug_bin, buildroot)
-  GSUploadIfNotPresent(gs_context, comp_debug_bin_path,
-                       GSURL_CHROME_DEBUG_BIN % afdo_spec)
-
-  # create_llvm_prof demands the name of the profiled binary exactly matches
-  # the name of the unstripped binary or it is named 'chrome.unstripped'.
-  # So create a symbolic link with the appropriate name.
-  local_debug_sym = os.path.join(local_dir, CHROME_UNSTRIPPED_NAME)
-  in_chroot_debug_bin = CHROME_DEBUG_BIN % {'root': '', 'board': board}
-  osutils.SafeUnlink(local_debug_sym)
-  os.symlink(in_chroot_debug_bin, local_debug_sym)
-
-  # Call create_llvm_prof tool to generated AFDO profile from 'perf' profile
-  # and upload it to GS. Need to call from within chroot since this tool
-  # was built inside chroot.
-  debug_sym = os.path.join(in_chroot_local_dir, CHROME_UNSTRIPPED_NAME)
-  # The name of the 'perf' file is based only on the version of chrome. The
-  # revision number is not included.
-  afdo_spec_no_rev = {
-      'package': chrome_pkg.package,
-      'arch': arch,
-      'version': chrome_pkg.version.split('_')[0],
-  }
-  perf_afdo_file = CHROME_PERF_AFDO_FILE % afdo_spec_no_rev
-  perf_afdo_path = os.path.join(in_chroot_local_dir, perf_afdo_file)
-  afdo_file = CHROME_AFDO_FILE % afdo_spec
-  afdo_path = os.path.join(in_chroot_local_dir, afdo_file)
-  afdo_cmd = [
-      AFDO_GENERATE_LLVM_PROF,
-      '--binary=%s' % debug_sym,
-      '--profile=%s' % perf_afdo_path,
-      '--out=%s' % afdo_path
-  ]
-  cros_build_lib.run(
-      afdo_cmd, enter_chroot=True, capture_output=True, print_cmd=True)
-
-  afdo_local_path = os.path.join(local_dir, afdo_file)
-  comp_afdo_path = CompressAFDOFile(afdo_local_path, buildroot)
-  uploaded_afdo_file = GSUploadIfNotPresent(gs_context, comp_afdo_path,
-                                            GSURL_CHROME_AFDO % afdo_spec)
-  return afdo_file, uploaded_afdo_file
-
-
-def CanGenerateAFDOData(board):
-  """Does this board has the capability of generating its own AFDO data?."""
-  return board in AFDO_DATA_GENERATORS_LLVM
-
-
-def FindLatestProfile(target, versions):
-  """Find latest profile that is usable by the target.
-
-  Args:
-    target: the target version
-    versions: a list of versions, and should be sorted
-
-  Returns:
-    latest profile that is older than the target
-  """
-  candidates = [x for x in versions if tuple(x) < tuple(target)]
-  if len(candidates) == 0:
-    return None
-  return candidates[-1]
-
-
-def PatchKernelEbuild(filename, version):
-  """Update the AFDO_PROFILE_VERSION string in the given kernel ebuild file.
-
-  Args:
-    filename: name of the ebuild
-    version: e.g., [61, 9752, 0, 0]
-  """
-  contents = []
-  for line in osutils.ReadFile(filename).splitlines():
-    if re.match(KERNEL_PROFILE_MATCH_PATTERN, line):
-      contents.append(KERNEL_PROFILE_WRITE_PATTERN % tuple(version) + '\n')
-    else:
-      contents.append(line + '\n')
-  osutils.WriteFile(filename, contents, atomic=True)
-
-
-def CWPProfileToVersionTuple(url):
-  """Convert a CWP profile url to a version tuple
-
-  Args:
-    url: for example, gs://chromeos-prebuilt/afdo-job/cwp/chrome/
-                      R65-3325.65-1519323840.afdo.xz
-
-  Returns:
-    A tuple of (milestone, major, minor, timestamp)
-  """
-  fn_mat = (
-      CWP_CHROME_PROFILE_NAME_PATTERN % tuple(r'([0-9]+)' for _ in range(0, 4)))
-  fn_mat.replace('.', '\\.')
-  return [int(x) for x in re.match(fn_mat, os.path.basename(url)).groups()]
-
-
-def GetCWPProfile(chrome_pkg: 'package_info.PackageInfo', source, _buildroot,
-                  gs_context):
-  """Try to find the latest suitable AFDO profile file for cwp.
-
-  Try to find the latest AFDO profile generated for current release
-  and architecture.
-
-  Args:
-    chrome_pkg: Chrome package information.
-    source: profile source
-    _buildroot: buildroot where AFDO data should be stored.
-    gs_context: GS context to retrieve data.
-
-  Returns:
-    Name of latest suitable AFDO profile file if one is found.
-    None otherwise.
-  """
-  ver_mat = r'([0-9]+)\.[0-9]+\.([0-9]+)\.([0-9]+)_rc-r[0-9]+'
-  target = [int(x) for x in re.match(ver_mat, chrome_pkg.vr).groups()]
-
-  # Check 2 most recent milestones.
-  #
-  # When a branch just happens, the milestone of master increases by 1. There
-  # will be no profile from that milestone until a dev release is pushed for a
-  # short period of time. Therefore, a profile from previous branches must be
-  # picked instead.
-  #
-  # Originally, we search toward root in the branch tree for a profile. Now we
-  # prefer to look at the previous milestone if there's no profile from current
-  # milestone, because:
-  #
-  # 1. dev channel has few samples. The profile quality is much better from
-  #    beta, which is always in a branch.
-  #
-  # 2. Master is actually closer to the branch tip than to the branch point,
-  #    assuming that most of the changes on a branch are cherry-picked from
-  #    master.
-  versions = []
-  for milestone in (target[0], target[0] - 1):
-    gs_ls_url = os.path.join(
-        GSURL_BASE_CWP, GSURL_CWP_SUBDIR[source],
-        CWP_CHROME_PROFILE_NAME_PATTERN % (milestone, '*', '*', '*'))
-    try:
-      res = gs_context.List(gs_ls_url)
-      versions.extend(CWPProfileToVersionTuple(x) for x in [r.url for r in res])
-    except gs.GSNoSuchKey:
-      pass
-
-  if not versions:
-    logging.info('profile not found for: %s', chrome_pkg.vr)
-    return None
-
-  # crbug.com/984153: Sort the CWP profiles only by (milestone, timestamp)
-  versions.sort(key=lambda x: (x[0], x[3]))
-  cand = FindLatestProfile(target, versions)
-  # reconstruct the filename and strip .xz
-  return (CWP_CHROME_PROFILE_NAME_PATTERN % tuple(cand))[:-3]
-
-
-def GetAvailableKernelProfiles():
-  """Get available profiles on specified gsurl.
-
-  Returns:
-    a dictionary that maps kernel version, e.g. "4_4" to a list of
-    [milestone, major, minor, timestamp]. E.g,
-    [62, 9901, 21, 1506581147]
-  """
-
-  gs_context = gs.GSContext()
-  gs_ls_url = os.path.join(KERNEL_PROFILE_URL, KERNEL_PROFILE_LS_PATTERN)
-  gs_match_url = os.path.join(KERNEL_PROFILE_URL, KERNEL_PROFILE_NAME_PATTERN)
-  try:
-    res = gs_context.List(gs_ls_url)
-  except gs.GSNoSuchKey:
-    logging.info('gs files not found: %s', gs_ls_url)
-    return {}
-
-  all_matches = [re.match(gs_match_url, x.url) for x in res]
-  matches = [x for x in all_matches if x]
-  versions = {}
-  for m in matches:
-    versions.setdefault(m.group(1), []).append([int(x) for x in m.groups()[1:]])
-  for v in versions:
-    # crbug.com/984153: Sort the kernel profiles only by (milestone, timestamp)
-    versions[v].sort(key=lambda x: (x[0], x[3]))
-  return versions
-
-
-def FindKernelEbuilds():
-  """Find all ebuilds that specify AFDO_PROFILE_VERSION.
-
-  The only assumption is that the ebuild files are named as the match pattern
-  in kver(). If it fails to recognize the ebuild filename, an error will be
-  thrown.
-
-  equery is not used because that would require enumerating the boards, which
-  is no easier than enumerating the kernel versions or ebuilds.
-
-  Returns:
-    a list of (ebuilds, kernel rev)
-  """
-
-  def kver(ebuild):
-    matched = re.match(r'.*/chromeos-kernel-([0-9]+_[0-9]+)-.+\.ebuild$',
-                       ebuild)
-    if matched:
-      return matched.group(1).replace('_', '.')
-    raise UnknownKernelVersion(
-        'Kernel version cannot be inferred from ebuild filename "%s".' % ebuild)
-
-  for fn in glob.glob(os.path.join(KERNEL_EBUILD_ROOT, '*', '*.ebuild')):
-    for line in osutils.ReadFile(fn).splitlines():
-      if re.match(KERNEL_PROFILE_MATCH_PATTERN, line):
-        yield (fn, kver(fn))
-        break
-
-
-def ProfileAge(profile_version):
-  """Tell the age of profile_version in days.
-
-  Args:
-    profile_version: [chrome milestone, cros major, cros minor, timestamp]
-                     e.g., [61, 9752, 0, 1500000000]
-
-  Returns:
-    Age of profile_version in days.
-  """
-  return (datetime.datetime.utcnow() -
-          datetime.datetime.utcfromtimestamp(profile_version[3])).days
-
-
-PROFILE_SOURCES = {
-    'benchmark': GetBenchmarkProfile,
-    'silvermont': GetCWPProfile,
-    'airmont': GetCWPProfile,
-    'broadwell': GetCWPProfile,
-}
diff --git a/cbuildbot/afdo_unittest.py b/cbuildbot/afdo_unittest.py
deleted file mode 100644
index a5579e7..0000000
--- a/cbuildbot/afdo_unittest.py
+++ /dev/null
@@ -1,771 +0,0 @@
-# Copyright 2017 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# Sometimes we poke 'private' AFDO methods, since that's the most direct way to
-# test what we're looking to test. That's OK.
-#
-# pylint: disable=protected-access
-
-"""Unit tests for afdo module."""
-
-import collections
-import datetime
-import json
-import os
-import time
-from unittest import mock
-
-from chromite.cbuildbot import afdo
-from chromite.lib import cros_build_lib
-from chromite.lib import cros_test_lib
-from chromite.lib import gs
-from chromite.lib import osutils
-from chromite.lib import path_util
-from chromite.lib.parser import package_info
-
-
-MockGsFile = collections.namedtuple('MockGsFile', ['url', 'creation_time'])
-
-
-def _benchmark_afdo_profile_name(major=0,
-                                 minor=0,
-                                 build=0,
-                                 patch=0,
-                                 rev=1,
-                                 merged_suffix=False,
-                                 compression_suffix=True):
-  suffix = '-merged' if merged_suffix else ''
-  result = 'chromeos-chrome-amd64-%d.%d.%d.%d_rc-r%d%s' % (major, minor, build,
-                                                           patch, rev, suffix)
-  result += afdo.AFDO_SUFFIX
-  if compression_suffix:
-    result += afdo.COMPRESSION_SUFFIX
-  return result
-
-
-class AfdoTest(cros_test_lib.MockTempDirTestCase):
-  """Unit test of afdo module."""
-
-  def testEnumerateMostRecentProfilesRaisesOnNoListing(self):
-    mock_gs = mock.Mock()
-    mock_gs.List = lambda *args, **kwargs: []
-    with self.assertRaises(ValueError):
-      afdo._EnumerateMostRecentProfiles(mock_gs, [1, 2, 3], 'some_url', None)
-
-  def testEnumerateMostRecentProfilesFindsTheNewestProfiles(self):
-
-    def mock_list(*_args, **_kwargs):
-      return [
-          MockGsFile(url='gs://foo/1_1', creation_time=None),
-          MockGsFile(url='gs://foo/2_2', creation_time=None),
-          MockGsFile(url='gs://foo/2_1', creation_time=None),
-          MockGsFile(url='gs://foo/1_2', creation_time=None),
-          MockGsFile(url='gs://foo/3_1', creation_time=None),
-      ]
-
-    mock_gs = mock.Mock()
-    mock_gs.List = mock_list
-
-    Version = collections.namedtuple('Version', ['major', 'minor'])
-
-    def parse_name(name):
-      major, minor = name.split('_')
-      # Note that the version key uses the *negative* minor number. So _1
-      # should be considered the newest. This is to be sure that we're ordering
-      # using these Version keys, rather than the strings.
-      return Version(int(major), -int(minor))
-
-    milestones = (1, 2, 4)
-    most_recent = afdo._EnumerateMostRecentProfiles(mock_gs, milestones, '',
-                                                    parse_name)
-    self.assertDictEqual(most_recent, {
-        1: 'gs://foo/1_1',
-        2: 'gs://foo/2_1',
-    })
-
-  def testParseProfileMatchesUncompressedProfiles(self):
-    # Local profiles will be uncompressed, and the profile parser needs to
-    # handle that.
-    profile_name = 'chromeos-chrome-amd64-76.0.3795.2_rc-r1.afdo'
-    profile_name_compressed = profile_name + '.bz2'
-    parsed = afdo._ParseBenchmarkProfileName(profile_name)
-    parsed_compressed = afdo._ParseBenchmarkProfileName(profile_name_compressed)
-    self.assertEqual(parsed, parsed_compressed)
-
-  def testEnumerateBenchmarkProfilesMatchesRealWorldNames(self):
-    enumerate_profiles = self.PatchObject(afdo, '_EnumerateMostRecentProfiles')
-    afdo._EnumerateMostRecentBenchmarkProfiles(object(), [1])
-    enumerate_profiles.assert_called_once()
-    parse_profile = enumerate_profiles.call_args_list[0][0][-1]
-
-    parsed = parse_profile('chromeos-chrome-amd64-57.0.2958.0_rc-r1.afdo.bz2')
-    self.assertEqual(parsed.major, 57)
-    parsed = parse_profile('chromeos-chrome-amd64-58.0.2959.0_rc-r1.afdo.bz2')
-    self.assertEqual(parsed.major, 58)
-
-    # ...Note that not all profiles have the _rc.
-    no_rc = parse_profile('chromeos-chrome-amd64-58.0.2959.0-r1.afdo.bz2')
-    self.assertEqual(no_rc, parsed)
-
-    # ...And we don't like merged profiles.
-    merged_profile = parse_profile(
-        'chromeos-chrome-amd64-58.0.2959.0-r1-merged.afdo.bz2')
-    self.assertIsNone(merged_profile)
-
-    profile_order = [
-        'chromeos-chrome-amd64-10.9.9.9_rc-r9.afdo.bz2',
-        'chromeos-chrome-amd64-9.10.9.9_rc-r9.afdo.bz2',
-        'chromeos-chrome-amd64-9.9.10.9_rc-r9.afdo.bz2',
-        'chromeos-chrome-amd64-9.9.9.10_rc-r9.afdo.bz2',
-        'chromeos-chrome-amd64-9.9.9.9_rc-r10.afdo.bz2',
-        'chromeos-chrome-amd64-9.9.9.9_rc-r9.afdo.bz2',
-    ]
-
-    for higher, lower in zip(profile_order, profile_order[1:]):
-      self.assertGreater(parse_profile(higher), parse_profile(lower))
-
-  def testEnumerateCWPProfilesMatchesRealWorldNames(self):
-    enumerate_profiles = self.PatchObject(afdo, '_EnumerateMostRecentProfiles')
-    afdo._EnumerateMostRecentCWPProfiles(object(), [1])
-    enumerate_profiles.assert_called_once()
-    parse_profile = enumerate_profiles.call_args_list[0][0][-1]
-
-    parsed = parse_profile('R75-3759.4-1555926322.afdo.xz')
-    self.assertEqual(parsed.major, 75)
-    parsed = parse_profile('R76-3759.4-1555926322.afdo.xz')
-    self.assertEqual(parsed.major, 76)
-
-    profile_order = [
-        'R10-9.9-9.afdo.xz',
-        'R9-10.9-9.afdo.xz',
-        'R9-9.10-9.afdo.xz',
-        'R9-9.9-10.afdo.xz',
-        'R9-9.9-9.afdo.xz',
-    ]
-
-    for higher, lower in zip(profile_order, profile_order[1:]):
-      self.assertGreater(parse_profile(higher), parse_profile(lower))
-
-  def testGenerateMergePlanMatchesProfilesAppropriately(self):
-    milestones = (1, 2, 3, 4)
-    gs_ctx = object()
-
-    def mock_enumerate(gs_context, milestones2, glob_url, _parse_profile_name):
-      self.assertIs(milestones, milestones2)
-      self.assertIs(gs_context, gs_ctx)
-
-      if afdo.GSURL_BASE_CWP in glob_url:
-        return {
-            1: 'gs://cwp/1',
-            2: 'gs://cwp/2',
-            4: 'gs://cwp/4',
-        }
-      assert afdo.GSURL_BASE_BENCH in glob_url
-      return {
-          1: 'gs://bench/1',
-          2: 'gs://bench/2',
-          3: 'gs://bench/3',
-      }
-
-    self.PatchObject(afdo, '_EnumerateMostRecentProfiles', mock_enumerate)
-    skipped, to_merge = afdo.GenerateReleaseProfileMergePlan(gs_ctx, milestones)
-    self.assertEqual(skipped, [3, 4])
-    self.assertDictEqual(to_merge, {
-        1: ('gs://cwp/1', 'gs://bench/1'),
-        2: ('gs://cwp/2', 'gs://bench/2'),
-    })
-
-  def testExecuteMergePlanWorks(self):
-    mock_gs = mock.Mock()
-    gs_copy = mock_gs.Copy
-    compress_file = self.PatchObject(cros_build_lib, 'CompressFile')
-    uncompress_file = self.PatchObject(cros_build_lib, 'UncompressFile')
-    merge_afdo_profiles = self.PatchObject(afdo, '_MergeAFDOProfiles')
-
-    # The only way to know for sure that we created a sufficient set of
-    # directories is a tryjob. Just make sure there are no side-effects.
-    self.PatchObject(osutils, 'SafeMakedirs')
-
-    merge_plan = {
-        1: ('gs://cwp/1.afdo.xz', 'gs://bench/1.afdo.bz2'),
-    }
-
-    build_root = '/build/root'
-    chroot = os.path.join(build_root, 'chroot')
-    merged_files = afdo.ExecuteReleaseProfileMergePlan(mock_gs, build_root,
-                                                       merge_plan)
-
-    self.assertSetEqual(set(merged_files.keys()), {1})
-    merged_output = merged_files[1]
-
-    def assert_call_args(the_mock, call_args):
-      self.assertEqual(the_mock.call_count, len(call_args))
-      the_mock.assert_has_calls(call_args)
-
-    assert_call_args(gs_copy, [
-        mock.call('gs://bench/1.afdo.bz2',
-                  chroot + '/tmp/afdo_data_merge/benchmark.afdo.bz2'),
-        mock.call('gs://cwp/1.afdo.xz',
-                  chroot + '/tmp/afdo_data_merge/cwp.afdo.xz'),
-    ])
-
-    assert_call_args(uncompress_file, [
-        mock.call(chroot + '/tmp/afdo_data_merge/benchmark.afdo.bz2',
-                  chroot + '/tmp/afdo_data_merge/benchmark.afdo'),
-        mock.call(chroot + '/tmp/afdo_data_merge/cwp.afdo.xz',
-                  chroot + '/tmp/afdo_data_merge/cwp.afdo'),
-    ])
-
-    uncompressed_merged_output = os.path.splitext(merged_output)[0]
-    uncompressed_chroot_merged_output = uncompressed_merged_output[len(chroot):]
-    assert_call_args(merge_afdo_profiles, [
-        mock.call([('/tmp/afdo_data_merge/cwp.afdo', 75),
-                   ('/tmp/afdo_data_merge/benchmark.afdo', 25)],
-                  uncompressed_chroot_merged_output,
-                  use_compbinary=True),
-    ])
-
-    assert_call_args(compress_file, [
-        mock.call(uncompressed_merged_output, merged_output),
-    ])
-
-  def testUploadReleaseProfilesUploadsAsExpected(self):
-    mock_gs = mock.Mock()
-    gs_copy = mock_gs.Copy
-    write_file = self.PatchObject(osutils, 'WriteFile')
-
-    global_tmpdir = '/global/tmp'
-    self.PatchObject(osutils, 'GetGlobalTempDir', return_value=global_tmpdir)
-
-    merge_plan = {
-        1: ('gs://cwp/1.afdo.xz', 'gs://bench/1.afdo.bz2'),
-        2: ('gs://cwp/2.afdo.xz', 'gs://bench/2.afdo.bz2'),
-    }
-
-    merge_results = {
-        1: '/tmp/foo.afdo.bz2',
-        2: '/tmp/bar.afdo.bz2',
-    }
-
-    run_id = '1234'
-    afdo.UploadReleaseProfiles(mock_gs, run_id, merge_plan, merge_results)
-
-    write_file.assert_called_once()
-    meta_file_local_location, meta_file_data = write_file.call_args_list[0][0]
-    self.assertEqual(meta_file_data, json.dumps(merge_plan))
-
-    self.assertTrue(meta_file_local_location.startswith(global_tmpdir))
-
-    def expected_upload_location(profile_version):
-      return os.path.join(afdo.GSURL_BASE_RELEASE, run_id,
-                          'profiles/m%d.afdo.bz2' % profile_version)
-
-    expected_copy_calls = [
-        mock.call(
-            merge_results[1],
-            expected_upload_location(1),
-            acl='public-read',
-            version=0),
-        mock.call(
-            merge_results[2],
-            expected_upload_location(2),
-            acl='public-read',
-            version=0),
-        mock.call(
-            meta_file_local_location,
-            os.path.join(afdo.GSURL_BASE_RELEASE, run_id, 'meta.json'),
-            acl='public-read',
-            version=0),
-    ]
-
-    gs_copy.assert_has_calls(expected_copy_calls)
-    self.assertEqual(gs_copy.call_count, len(expected_copy_calls))
-
-  def runCreateAndUploadMergedAFDOProfileOnce(self, upload_ok=True, **kwargs):
-    if 'unmerged_name' not in kwargs:
-      # Match everything.
-      kwargs['unmerged_name'] = _benchmark_afdo_profile_name(major=9999)
-
-    Mocks = collections.namedtuple('Mocks', [
-        'gs_context',
-        'run_command',
-        'uncompress_file',
-        'compress_file',
-        'upload',
-        'remove_indirect_call_targets',
-    ])
-
-    def MockList(*_args, **_kwargs):
-      files = [
-          _benchmark_afdo_profile_name(major=10, build=9),
-          _benchmark_afdo_profile_name(major=10, build=10),
-          _benchmark_afdo_profile_name(major=10, build=10, merged_suffix=True),
-          _benchmark_afdo_profile_name(major=10, build=11),
-          _benchmark_afdo_profile_name(major=10, build=12),
-          _benchmark_afdo_profile_name(major=10, build=13),
-          _benchmark_afdo_profile_name(major=10, build=13, merged_suffix=True),
-          _benchmark_afdo_profile_name(major=10, build=13, patch=1),
-          _benchmark_afdo_profile_name(major=10, build=13, patch=2),
-          _benchmark_afdo_profile_name(
-              major=10, build=13, patch=2, merged_suffix=True),
-          _benchmark_afdo_profile_name(major=11, build=14),
-          _benchmark_afdo_profile_name(major=11, build=14, merged_suffix=True),
-          _benchmark_afdo_profile_name(major=11, build=15),
-      ]
-
-      results = []
-      for i, name in enumerate(files):
-        url = os.path.join(afdo.GSURL_BASE_BENCH, name)
-        now = datetime.datetime(year=1990, month=1, day=1 + i)
-        results.append(MockGsFile(url=url, creation_time=now))
-      return results
-
-    mock_gs = mock.Mock()
-    mock_gs.List = MockList
-    run_command = self.PatchObject(cros_build_lib, 'run')
-    uncompress_file = self.PatchObject(cros_build_lib, 'UncompressFile')
-    compress_file = self.PatchObject(cros_build_lib, 'CompressFile')
-    upload = self.PatchObject(afdo, 'GSUploadIfNotPresent')
-    remove_indirect_call_targets = self.PatchObject(
-        afdo, '_RemoveIndirectCallTargetsFromProfile')
-    upload.return_value = upload_ok
-    merged_name, uploaded = afdo.CreateAndUploadMergedAFDOProfile(
-        mock_gs, '/buildroot', **kwargs)
-    return merged_name, uploaded, Mocks(
-        gs_context=mock_gs,
-        run_command=run_command,
-        uncompress_file=uncompress_file,
-        compress_file=compress_file,
-        upload=upload,
-        remove_indirect_call_targets=remove_indirect_call_targets)
-
-  def testCreateAndUploadMergedAFDOProfileMergesBranchProfiles(self):
-    unmerged_name = _benchmark_afdo_profile_name(major=10, build=13, patch=99)
-
-    _, uploaded, mocks = self.runCreateAndUploadMergedAFDOProfileOnce(
-        recent_to_merge=5,
-        unmerged_name=unmerged_name)
-    self.assertTrue(uploaded)
-
-    def _afdo_name(major, build, patch=0, merged_suffix=False):
-      return _benchmark_afdo_profile_name(
-          major=major,
-          build=build,
-          patch=patch,
-          merged_suffix=merged_suffix,
-          compression_suffix=False)
-
-    expected_unordered_args = [
-        '-output=/tmp/raw-' +
-        _afdo_name(major=10, build=13, patch=2, merged_suffix=True),
-        '-weighted-input=1,/tmp/' + _afdo_name(major=10, build=11),
-        '-weighted-input=1,/tmp/' + _afdo_name(major=10, build=12),
-        '-weighted-input=1,/tmp/' + _afdo_name(major=10, build=13),
-        '-weighted-input=1,/tmp/' + _afdo_name(major=10, build=13, patch=1),
-        '-weighted-input=1,/tmp/' + _afdo_name(major=10, build=13, patch=2),
-    ]
-
-    # Note that these should all be in-chroot names.
-    expected_ordered_args = ['llvm-profdata', 'merge', '-sample']
-
-    args = mocks.run_command.call_args[0][0]
-    ordered_args = args[:len(expected_ordered_args)]
-    self.assertEqual(ordered_args, expected_ordered_args)
-
-    unordered_args = args[len(expected_ordered_args):]
-    self.assertCountEqual(unordered_args, expected_unordered_args)
-    self.assertEqual(mocks.gs_context.Copy.call_count, 5)
-
-  def testCreateAndUploadMergedAFDOProfileRemovesIndirectCallTargets(self):
-    unmerged_name = _benchmark_afdo_profile_name(major=10, build=13, patch=99)
-
-    merged_name, uploaded, mocks = self.runCreateAndUploadMergedAFDOProfileOnce(
-        recent_to_merge=2,
-        unmerged_name=unmerged_name)
-    self.assertTrue(uploaded)
-
-    def _afdo_name(major, build, patch=0, merged_suffix=False):
-      return _benchmark_afdo_profile_name(
-          major=major,
-          build=build,
-          patch=patch,
-          merged_suffix=merged_suffix,
-          compression_suffix=False)
-
-    merge_output_name = 'raw-' + _afdo_name(
-        major=10, build=13, patch=2, merged_suffix=True)
-    self.assertNotEqual(merged_name, merge_output_name)
-
-    expected_unordered_args = [
-        '-output=/tmp/' + merge_output_name,
-        '-weighted-input=1,/tmp/' + _afdo_name(major=10, build=13, patch=1),
-        '-weighted-input=1,/tmp/' + _afdo_name(major=10, build=13, patch=2),
-    ]
-
-    # Note that these should all be in-chroot names.
-    expected_ordered_args = ['llvm-profdata', 'merge', '-sample']
-    args = mocks.run_command.call_args[0][0]
-    ordered_args = args[:len(expected_ordered_args)]
-    self.assertEqual(ordered_args, expected_ordered_args)
-
-    unordered_args = args[len(expected_ordered_args):]
-    self.assertCountEqual(unordered_args, expected_unordered_args)
-
-    mocks.remove_indirect_call_targets.assert_called_once_with(
-        '/tmp/' + merge_output_name, '/tmp/' + merged_name)
-
-  def testCreateAndUploadMergedAFDOProfileWorksInTheHappyCase(self):
-    merged_name, uploaded, mocks = self.runCreateAndUploadMergedAFDOProfileOnce(
-        recent_to_merge=5)
-
-    self.assertTrue(uploaded)
-    # Note that we always return the *basename*
-    self.assertEqual(
-        merged_name,
-        _benchmark_afdo_profile_name(
-            major=11, build=15, merged_suffix=True, compression_suffix=False))
-
-    self.assertTrue(uploaded)
-    mocks.run_command.assert_called_once()
-
-    # Note that these should all be in-chroot names.
-    expected_ordered_args = ['llvm-profdata', 'merge', '-sample']
-
-    def _afdo_name(major, build, patch=0, merged_suffix=False):
-      return _benchmark_afdo_profile_name(
-          major=major,
-          build=build,
-          patch=patch,
-          merged_suffix=merged_suffix,
-          compression_suffix=False)
-
-    input_afdo_names = [
-        _afdo_name(major=10, build=13),
-        _afdo_name(major=10, build=13, patch=1),
-        _afdo_name(major=10, build=13, patch=2),
-        _afdo_name(major=11, build=14),
-        _afdo_name(major=11, build=15),
-    ]
-
-    output_afdo_name = _afdo_name(major=11, build=15, merged_suffix=True)
-    expected_unordered_args = ['-output=/tmp/raw-' + output_afdo_name]
-    expected_unordered_args += [
-        '-weighted-input=1,/tmp/' + n for n in input_afdo_names
-    ]
-
-    args = mocks.run_command.call_args[0][0]
-    ordered_args = args[:len(expected_ordered_args)]
-    self.assertEqual(ordered_args, expected_ordered_args)
-
-    unordered_args = args[len(expected_ordered_args):]
-    self.assertCountEqual(unordered_args, expected_unordered_args)
-    self.assertEqual(mocks.gs_context.Copy.call_count, 5)
-
-    self.assertEqual(mocks.uncompress_file.call_count, 5)
-
-    def call_for(name):
-      basis = '/buildroot/chroot/tmp/' + name
-      return mock.call(basis + afdo.COMPRESSION_SUFFIX, basis)
-
-    mocks.uncompress_file.assert_has_calls(
-        any_order=True, calls=[call_for(n) for n in input_afdo_names])
-
-    compressed_output_afdo_name = output_afdo_name + afdo.COMPRESSION_SUFFIX
-    compressed_target = '/buildroot/chroot/tmp/' + compressed_output_afdo_name
-    mocks.compress_file.assert_called_once()
-    args = mocks.compress_file.call_args[0]
-    self.assertEqual(args, (
-        compressed_target[:-len(afdo.COMPRESSION_SUFFIX)],
-        compressed_target,
-    ))
-
-    mocks.upload.assert_called_once()
-    args = mocks.upload.call_args[0]
-
-    self.assertEqual(args, (
-        mocks.gs_context,
-        compressed_target,
-        '%s/%s' % (afdo.GSURL_BASE_BENCH, compressed_output_afdo_name),
-    ))
-
-  def testCreateAndUploadMergedAFDOProfileSucceedsIfUploadFails(self):
-    merged_name, uploaded, _ = self.runCreateAndUploadMergedAFDOProfileOnce(
-        upload_ok=False)
-    self.assertIsNotNone(merged_name)
-    self.assertFalse(uploaded)
-
-  def testMergeIsOKIfWeFindFewerProfilesThanWeWant(self):
-    merged_name, uploaded, mocks = self.runCreateAndUploadMergedAFDOProfileOnce(
-        recent_to_merge=1000, max_age_days=1000)
-    self.assertTrue(uploaded)
-    self.assertIsNotNone(merged_name)
-    self.assertEqual(mocks.gs_context.Copy.call_count, 9)
-
-  def testNoProfileIsGeneratedIfNoFilesBeforeMergedNameExist(self):
-    merged_name, uploaded, _ = self.runCreateAndUploadMergedAFDOProfileOnce(
-            unmerged_name=_benchmark_afdo_profile_name())
-    self.assertIsNone(merged_name)
-    self.assertFalse(uploaded)
-
-    merged_name, uploaded, _ = self.runCreateAndUploadMergedAFDOProfileOnce(
-        unmerged_name=_benchmark_afdo_profile_name(major=10, build=8))
-    self.assertIsNone(merged_name)
-    self.assertFalse(uploaded)
-
-    merged_name, uploaded, _ = self.runCreateAndUploadMergedAFDOProfileOnce(
-        unmerged_name=_benchmark_afdo_profile_name(major=10, build=9))
-    self.assertIsNone(merged_name)
-    self.assertFalse(uploaded)
-
-    merged_name, uploaded, _ = self.runCreateAndUploadMergedAFDOProfileOnce(
-        unmerged_name=_benchmark_afdo_profile_name(major=10, build=10))
-    self.assertIsNotNone(merged_name)
-    self.assertTrue(uploaded)
-
-  def testNoFilesAfterUnmergedNameAreIncluded(self):
-    max_name = _benchmark_afdo_profile_name(major=10, build=11)
-    merged_name, uploaded, mocks = self.runCreateAndUploadMergedAFDOProfileOnce(
-        unmerged_name=max_name)
-
-    self.assertEqual(
-        _benchmark_afdo_profile_name(
-            major=10, build=11, merged_suffix=True, compression_suffix=False),
-        merged_name)
-    self.assertTrue(uploaded)
-
-    def _afdo_name(major, build, merged_suffix=False):
-      return _benchmark_afdo_profile_name(
-          major=major,
-          build=build,
-          merged_suffix=merged_suffix,
-          compression_suffix=False)
-
-    # Note that these should all be in-chroot names.
-    expected_ordered_args = ['llvm-profdata', 'merge', '-sample']
-    expected_unordered_args = [
-        '-output=/tmp/raw-' +
-        _afdo_name(major=10, build=11, merged_suffix=True),
-        '-weighted-input=1,/tmp/' + _afdo_name(major=10, build=9),
-        '-weighted-input=1,/tmp/' + _afdo_name(major=10, build=10),
-        '-weighted-input=1,/tmp/' + _afdo_name(major=10, build=11),
-    ]
-
-    args = mocks.run_command.call_args[0][0]
-    ordered_args = args[:len(expected_ordered_args)]
-    self.assertEqual(ordered_args, expected_ordered_args)
-
-    unordered_args = args[len(expected_ordered_args):]
-    self.assertCountEqual(unordered_args, expected_unordered_args)
-
-    self.assertEqual(mocks.gs_context.Copy.call_count, 3)
-    self.assertEqual(mocks.uncompress_file.call_count, 3)
-
-  def testMergeDoesntHappenIfNoProfilesAreMerged(self):
-    runs = [
-        self.runCreateAndUploadMergedAFDOProfileOnce(recent_to_merge=1),
-        self.runCreateAndUploadMergedAFDOProfileOnce(max_age_days=0),
-    ]
-
-    for merged_name, uploaded, mocks in runs:
-      self.assertIsNone(merged_name)
-      self.assertFalse(uploaded)
-      mocks.gs_context.Copy.assert_not_called()
-      mocks.run_command.assert_not_called()
-      mocks.uncompress_file.assert_not_called()
-      mocks.compress_file.assert_not_called()
-      mocks.upload.assert_not_called()
-
-  def testRemoveIndirectCallTargetsActuallyAppearsToWork(self):
-    run_command = self.PatchObject(cros_build_lib, 'run')
-    path_exists = self.PatchObject(os.path, 'exists', return_value=False)
-
-    input_path = '/input/path'
-    input_path_txt = input_path + '.txt'
-    output_path = '/output/path'
-    output_path_txt = output_path + '.txt'
-    afdo._RemoveIndirectCallTargetsFromProfile(input_path, output_path)
-
-    self.assertEqual(run_command.call_count, 3)
-    merge_to_text, removal, merge_to_bin = run_command.call_args_list
-
-    path_exists.insert_called_with(os.path.join('/chroot', input_path_txt))
-    self.assertEqual(
-        merge_to_text,
-        mock.call(
-            [
-                'llvm-profdata',
-                'merge',
-                '-sample',
-                '-output=%s' % input_path_txt,
-                '-text',
-                input_path,
-            ],
-            enter_chroot=True,
-            print_cmd=True,
-        ))
-
-    # Probably no value in checking for the actual script name.
-    script_name = removal[0][0][0]
-    removal.assert_equal(
-        removal,
-        mock.call(
-            [
-                script_name,
-                '--input=%s' % input_path_txt,
-                '--output=%s' % output_path_txt,
-            ],
-            enter_chroot=True,
-            print_cmd=True,
-        ))
-
-    self.assertEqual(
-        merge_to_bin,
-        mock.call(
-            [
-                'llvm-profdata',
-                'merge',
-                '-sample',
-                '-output=' + output_path,
-                output_path_txt,
-            ],
-            enter_chroot=True,
-            print_cmd=True,
-        ))
-
-  def testFindLatestProfile(self):
-    versions = [[1, 0, 0, 0], [1, 2, 3, 4], [2, 3, 4, 1], [2, 2, 2, 2]]
-    self.assertEqual(afdo.FindLatestProfile([1, 0, 0], versions), None)
-    self.assertEqual(afdo.FindLatestProfile([1, 2, 0], versions), [1, 0, 0, 0])
-    self.assertEqual(afdo.FindLatestProfile([9, 9, 9], versions), [2, 2, 2, 2])
-
-  def testPatchKernelEbuild(self):
-    before = [
-        'The following line contains the version:',
-        'AFDO_PROFILE_VERSION="R63-9901.21-1506581597"', 'It should be changed.'
-    ]
-    after = [
-        'The following line contains the version:',
-        'AFDO_PROFILE_VERSION="R12-3456.78-9876543210"', 'It should be changed.'
-    ]
-    tf = os.path.join(self.tempdir, 'test.ebuild')
-    osutils.WriteFile(tf, '\n'.join(before))
-    afdo.PatchKernelEbuild(tf, [12, 3456, 78, 9876543210])
-    x = osutils.ReadFile(tf).splitlines()
-    self.assertEqual(after, x)
-
-  def testGetAvailableKernelProfiles(self):
-
-    def MockGsList(path):
-      unused = {
-          'content_length': None,
-          'creation_time': None,
-          'generation': None,
-          'metageneration': None
-      }
-      path = path.replace('*', '%s')
-      return [
-          gs.GSListResult(
-              url=(path % ('4.4', 'R63-9901.21-1506581597')), **unused),
-          gs.GSListResult(
-              url=(path % ('4.4', 'R63-9999.99-1500000000')), **unused),
-          gs.GSListResult(
-              url=(path % ('3.8', 'R61-9765.70-1506575230')), **unused),
-      ]
-
-    self.PatchObject(gs.GSContext,
-                     'List', lambda _, path, **kwargs: MockGsList(path))
-    profiles = afdo.GetAvailableKernelProfiles()
-    self.assertEqual([[61, 9765, 70, 1506575230]], profiles['3.8'])
-    self.assertEqual([[63, 9999, 99, 1500000000], [63, 9901, 21, 1506581597]],
-                     profiles['4.4'])
-
-  def testFindKernelEbuilds(self):
-    ebuilds = [(os.path.basename(ebuild[0]), ebuild[1])
-               for ebuild in afdo.FindKernelEbuilds()]
-    self.assertIn(('chromeos-kernel-4_4-9999.ebuild', '4.4'), ebuilds)
-    self.assertIn(('chromeos-kernel-4_19-9999.ebuild', '4.19'), ebuilds)
-    self.assertIn(('chromeos-kernel-5_4-9999.ebuild', '5.4'), ebuilds)
-
-  def testProfileAge(self):
-    self.assertEqual(0, afdo.ProfileAge([0, 0, 0, int(time.time())]))
-    self.assertEqual(1, afdo.ProfileAge([0, 0, 0, int(time.time() - 86400)]))
-
-  def testGetCWPProfile(self):
-    profiles = [
-        'R62-3202.43-320243.afdo.xz', 'R63-3223.0-233200.afdo.xz',
-        'R63-3239.20-323920.afdo.xz', 'R63-3239.42-323942.afdo.xz',
-        'R63-3239.50-323950.afdo.xz', 'R63-3239.50-323999.afdo.xz',
-        'R64-3280.5-328005.afdo.xz', 'R64-3282.41-328241.afdo.xz',
-        'R65-3299.0-329900.afdo.xz'
-    ]
-
-    def MockGsList(path):
-      unused = {
-          'content_length': None,
-          'creation_time': None,
-          'generation': None,
-          'metageneration': None
-      }
-      return [
-          gs.GSListResult(url=os.path.join(path, f), **unused) for f in profiles
-      ]
-
-    self.PatchObject(gs.GSContext,
-                     'List', lambda _, path, **kwargs: MockGsList(path))
-
-    def _test(version, idx):
-      pkg_info = package_info.PackageInfo(version=version)
-      profile = afdo.GetCWPProfile(pkg_info, 'silvermont', 'unused',
-                                   gs.GSContext())
-      # Expect the most recent profile on the same branch.
-      self.assertEqual(profile, profiles[idx][:-3])
-
-    _test('66.0.3300.0_rc-r1', 8)
-    _test('65.0.3283.0_rc-r1', 7)
-    _test('65.0.3283.1_rc-r1', 7)
-    _test('64.0.3282.42_rc-r1', 7)
-    _test('64.0.3282.40_rc-r1', 6)
-    _test('63.0.3239.30_rc-r1', 2)
-    _test('63.0.3239.42_rc-r0', 2)
-    _test('63.0.3239.10_rc-r1', 1)
-
-  def testCWPProfileToVersionTuple(self):
-    self.assertEqual(
-        afdo.CWPProfileToVersionTuple('gs://chromeos-prebuilt/afdo-job/cwp/'
-                                      'chrome/R66-3325.65-1519321598.afdo.xz'),
-        [66, 3325, 65, 1519321598])
-    self.assertEqual(
-        afdo.CWPProfileToVersionTuple('R66-3325.65-1519321598.afdo.xz'),
-        [66, 3325, 65, 1519321598])
-
-  def testPatchChromeEbuildAFDOFile(self):
-    before = [
-        'The following line contains the version:',
-        'AFDO_FILE["benchmark"]="chromeos-chrome-amd64-67.0.3379.0_rc-r1.afdo"',
-        'AFDO_FILE["silvermont"]="R67-3359.31-1522059092.afdo"',
-        'AFDO_FILE["airmont"]="airmont_before.afdo"',
-        'AFDO_FILE["broadwell"]="broadwell_before.afdo"',
-        'It should be changed.'
-    ]
-    after = [
-        'The following line contains the version:',
-        'AFDO_FILE["benchmark"]="chromeos-chrome-amd64-67.0.3388.0_rc-r1.afdo"',
-        'AFDO_FILE["silvermont"]="R67-3360.42-153456789.afdo"',
-        'AFDO_FILE["airmont"]="airmont_after.afdo"',
-        'AFDO_FILE["broadwell"]="broadwell_after.afdo"', 'It should be changed.'
-    ]
-
-    self.PatchObject(path_util, 'FromChrootPath', lambda x: x)
-
-    tf = os.path.join(self.tempdir, 'test.ebuild')
-    osutils.WriteFile(tf, '\n'.join(before))
-    afdo.PatchChromeEbuildAFDOFile(
-        tf, {
-            'benchmark': 'chromeos-chrome-amd64-67.0.3388.0_rc-r1.afdo',
-            'broadwell': 'broadwell_after.afdo',
-            'airmont': 'airmont_after.afdo',
-            'silvermont': 'R67-3360.42-153456789.afdo'
-        })
-    x = osutils.ReadFile(tf).splitlines()
-    self.assertEqual(after, x)
diff --git a/cbuildbot/builders/fuzzer_builders.py b/cbuildbot/builders/fuzzer_builders.py
index 9452d82..0897f09 100644
--- a/cbuildbot/builders/fuzzer_builders.py
+++ b/cbuildbot/builders/fuzzer_builders.py
@@ -27,4 +27,3 @@
     self._RunStage(build_stages.BuildPackagesStage, board,
                    record_packages_under_test=False)
     self._RunStage(artifact_stages.GenerateSysrootStage, board)
-    self._RunStage(artifact_stages.ArchiveStage, board, builder_run=self._run)
diff --git a/cbuildbot/builders/release_profile_builders.py b/cbuildbot/builders/release_profile_builders.py
deleted file mode 100644
index c5c8e6a..0000000
--- a/cbuildbot/builders/release_profile_builders.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright 2019 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""'Builders' that just run actions in the chroot without building boards."""
-
-from chromite.cbuildbot.builders import generic_builders
-from chromite.cbuildbot.stages import afdo_stages
-from chromite.cbuildbot.stages import build_stages
-
-
-class ReleaseProfileMergeBuilder(generic_builders.ManifestVersionedBuilder):
-  """Builder that generates merged profiles for Chrome."""
-
-  def RunStages(self):
-    """Run stages for the release AFDO profile merge builder."""
-    assert not self._run.config.boards
-
-    # All we need is a reasonably functional SDK, so we can run llvm-profdata
-    # and a few gsutil commands in it.
-    self._RunStage(build_stages.UprevStage)
-    self._RunStage(build_stages.InitSDKStage)
-    self._RunStage(build_stages.UpdateSDKStage)
-    self._RunStage(afdo_stages.AFDOReleaseProfileMergerStage)
diff --git a/cbuildbot/builders/simple_builders.py b/cbuildbot/builders/simple_builders.py
index f56835a..57cd015 100644
--- a/cbuildbot/builders/simple_builders.py
+++ b/cbuildbot/builders/simple_builders.py
@@ -8,10 +8,8 @@
 import logging
 import traceback
 
-from chromite.cbuildbot import afdo
 from chromite.cbuildbot import manifest_version
 from chromite.cbuildbot.builders import generic_builders
-from chromite.cbuildbot.stages import afdo_stages
 from chromite.cbuildbot.stages import android_stages
 from chromite.cbuildbot.stages import artifact_stages
 from chromite.cbuildbot.stages import build_stages
@@ -30,7 +28,6 @@
 from chromite.lib import failures_lib
 from chromite.lib import parallel
 from chromite.lib import results_lib
-from chromite.lib import toolchain_util
 
 
 # TODO: SimpleBuilder needs to be broken up big time.
@@ -199,24 +196,6 @@
     if config.moblab_vm_tests:
       stage_list += [[vm_test_stages.MoblabVMTestStage, board]]
 
-    if config.afdo_generate:
-      stage_list += [[afdo_stages.AFDODataGenerateStage, board]]
-
-    if config.afdo_generate_async:
-      stage_list += [[afdo_stages.GenerateBenchmarkAFDOStage, board]]
-
-    if config.orderfile_generate:
-      stage_list += [[afdo_stages.GenerateChromeOrderfileStage, board]]
-
-    if config.orderfile_verify:
-      stage_list += [[afdo_stages.UploadVettedOrderfileStage, board]]
-
-    if config.kernel_afdo_verify:
-      stage_list += [[afdo_stages.UploadVettedKernelAFDOStage, board]]
-
-    if config.chrome_afdo_verify:
-      stage_list += [[afdo_stages.UploadVettedChromeAFDOStage, board]]
-
     stage_list += [
         [release_stages.SignerTestStage, board, archive_stage],
         [release_stages.SigningStage, board],
@@ -333,62 +312,7 @@
     task_runner = self._RunBackgroundStagesForBoardAndMarkAsSuccessful
     with parallel.BackgroundTaskRunner(task_runner) as queue:
       for builder_run, board in tasks:
-        # Skip generate benchmark AFDO if the board is not suitable or
-        # if it's already in the bucket
-        if (builder_run.config.afdo_generate_async and
-            toolchain_util.CanGenerateAFDOData(board) and
-            toolchain_util.CheckAFDOArtifactExists(
-                buildroot=builder_run.buildroot,
-                chrome_root=builder_run.options.chrome_root,
-                board=board,
-                target='benchmark_afdo')):
-          continue
-
-        # Only generate orderfile if Chrome is uprevved since last generation.
-        if (builder_run.config.orderfile_generate and
-            toolchain_util.CheckAFDOArtifactExists(
-                buildroot=builder_run.buildroot,
-                chrome_root=builder_run.options.chrome_root,
-                board=board,
-                target='orderfile_generate')):
-          continue
-
-        # Update Chrome ebuild with unvetted orderfile
-        if builder_run.config.orderfile_verify:
-          # Skip verifying orderfile if it's already verified.
-          if toolchain_util.CheckAFDOArtifactExists(
-              buildroot=builder_run.buildroot,
-              chrome_root=builder_run.options.chrome_root,
-              board=board,
-              target='orderfile_verify'):
-            continue
-          self._RunStage(afdo_stages.OrderfileUpdateChromeEbuildStage,
-                         board, builder_run=builder_run)
-
-        if builder_run.config.kernel_afdo_verify:
-          # Skip verifying kernel AFDO if it's already verified.
-          if toolchain_util.CheckAFDOArtifactExists(
-              buildroot=builder_run.buildroot,
-              chrome_root=builder_run.options.chrome_root,
-              board=board,
-              target='kernel_afdo'):
-            continue
-          self._RunStage(afdo_stages.KernelAFDOUpdateEbuildStage,
-                         board, builder_run=builder_run)
-
-        if builder_run.config.chrome_afdo_verify:
-          # Skip verifying Chrome AFDO if both benchmark and CWP are verified.
-          if toolchain_util.CheckAFDOArtifactExists(
-              buildroot=builder_run.buildroot,
-              chrome_root=builder_run.options.chrome_root,
-              board=board,
-              target='chrome_afdo'):
-            continue
-          self._RunStage(afdo_stages.ChromeAFDOUpdateEbuildStage,
-                         board, builder_run=builder_run)
-
-        # Run BuildPackages in the foreground, generating or using AFDO data
-        # if requested.
+        # Run BuildPackages in the foreground.
         kwargs = {'builder_run': builder_run}
         if builder_run.config.afdo_generate_min:
           kwargs['afdo_generate_min'] = True
@@ -398,29 +322,6 @@
         self._RunStage(build_stages.BuildPackagesStage, board,
                        update_metadata=True, **kwargs)
 
-        if (builder_run.config.afdo_generate_min and
-            afdo.CanGenerateAFDOData(board)):
-          # Generate the AFDO data before allowing any other tasks to run.
-          self._RunStage(build_stages.BuildImageStage, board, **kwargs)
-          self._RunStage(artifact_stages.UploadTestArtifactsStage, board,
-                         builder_run=builder_run,
-                         suffix='[afdo_generate_min]')
-          for suite in builder_run.config.hw_tests:
-            self._RunStage(test_stages.SkylabHWTestStage, board, suite,
-                           builder_run=builder_run)
-          self._RunStage(afdo_stages.AFDODataGenerateStage, board,
-                         builder_run=builder_run)
-
-        if (builder_run.config.afdo_generate_min and
-            builder_run.config.afdo_update_chrome_ebuild):
-          self._RunStage(afdo_stages.AFDOUpdateChromeEbuildStage,
-                         builder_run=builder_run)
-
-        if (builder_run.config.afdo_generate_min and
-            builder_run.config.afdo_update_kernel_ebuild):
-          self._RunStage(afdo_stages.AFDOUpdateKernelEbuildStage,
-                         builder_run=builder_run)
-
         # Kick off our background stages.
         queue.put([builder_run, board])
 
@@ -524,48 +425,35 @@
         without completing if it raises ExitEarlyException.
       completion_successful: Whether the compeletion_stage succeeded.
     """
-    try:
-      # When (afdo_update_ebuild and not afdo_generate_min) is True,
-      # if completion_stage passed, need to run
-      # AFDOUpdateChromeEbuildStage to prepare for pushing commits to masters;
-      # if it's a master_chrome_pfq build and compeletion_stage failed,
-      # need to run AFDOUpdateChromeEbuildStage to prepare for pushing commits
-      # to a staging branch.
-      if completion_successful and not self._run.config.afdo_generate_min:
-        if self._run.config.afdo_update_chrome_ebuild:
-          self._RunStage(afdo_stages.AFDOUpdateChromeEbuildStage)
-        if self._run.config.afdo_update_kernel_ebuild:
-          self._RunStage(afdo_stages.AFDOUpdateKernelEbuildStage)
-    finally:
-      if self._run.config.master:
-        self._RunStage(report_stages.SlaveFailureSummaryStage)
+    if self._run.config.master:
+      self._RunStage(report_stages.SlaveFailureSummaryStage)
 
-      if (config_lib.IsCanaryMaster(self._run) or
-          (self._run.config.master and
-           self._run.config.build_type == constants.FULL_TYPE)):
-        if build_finished and not self._run.config.basic_builder:
-          self._RunStage(completion_stages.UpdateChromeosLKGMStage)
-        else:
-          logging.info(
-              'Skipping UpdateChromeosLKGMStage, '
-              'build_successful=%d completion_successful=%d '
-              'build_finished=%d', was_build_successful, completion_successful,
-              build_finished)
+    if (config_lib.IsCanaryMaster(self._run) or
+        (self._run.config.master and
+         self._run.config.build_type == constants.FULL_TYPE)):
+      if build_finished and not self._run.config.basic_builder:
+        self._RunStage(completion_stages.UpdateChromeosLKGMStage)
+      else:
+        logging.info(
+            'Skipping UpdateChromeosLKGMStage, '
+            'build_successful=%d completion_successful=%d '
+            'build_finished=%d', was_build_successful, completion_successful,
+            build_finished)
 
-      if self._run.config.push_overlays:
-        publish = (was_build_successful and completion_successful and
-                   build_finished)
-        # CQ and Master Chrome PFQ no longer publish uprevs. For Master Chrome
-        # PFQ this is because this duty is being transitioned to the Chrome
-        # PUpr in the PCQ world. See http://go/pupr.
-        # There is no easy way to disable this in ChromeOS config,
-        # so hack the check here.
+    if self._run.config.push_overlays:
+      publish = (was_build_successful and completion_successful and
+                 build_finished)
+      # CQ and Master Chrome PFQ no longer publish uprevs. For Master Chrome
+      # PFQ this is because this duty is being transitioned to the Chrome
+      # PUpr in the PCQ world. See http://go/pupr.
+      # There is no easy way to disable this in ChromeOS config,
+      # so hack the check here.
 
-        if publish and config_lib.IsMasterAndroidPFQ(self._run.config):
-          self._RunStage(android_stages.UprevAndroidStage)
-          self._RunStage(android_stages.AndroidMetadataStage)
-        self._RunStage(completion_stages.PublishUprevChangesStage,
-                       self.sync_stage, publish)
+      if publish and config_lib.IsMasterAndroidPFQ(self._run.config):
+        self._RunStage(android_stages.UprevAndroidStage)
+        self._RunStage(android_stages.AndroidMetadataStage)
+      self._RunStage(completion_stages.PublishUprevChangesStage,
+                     self.sync_stage, publish)
 
   def RunStages(self):
     """Runs simple builder logic and publishes information to overlays."""
diff --git a/cbuildbot/commands.py b/cbuildbot/commands.py
index 77099b0..f8dfa92 100644
--- a/cbuildbot/commands.py
+++ b/cbuildbot/commands.py
@@ -51,8 +51,8 @@
 
 
 _PACKAGE_FILE = '%(buildroot)s/src/scripts/cbuildbot_package.list'
-CHROME_KEYWORDS_FILE = ('%(buildroot)s/%(chroot)s'
-                        '/build/%(board)s/etc/portage/package.keywords/chrome')
+CHROME_KEYWORDS_FILE = ('%(buildroot)s/%(chroot)s/build/%(board)s'
+                        '/etc/portage/package.accept_keywords/chrome')
 CHROME_UNMASK_FILE = ('%(buildroot)s/%(chroot)s'
                       '/build/%(board)s/etc/portage/package.unmask/chrome')
 _CROS_ARCHIVE_URL = 'CROS_ARCHIVE_URL'
@@ -1240,8 +1240,7 @@
     suite_args=None,
     job_keyvals=None,
     quota_account=None,
-    upload_crashes=False,
-  ):
+    upload_crashes=False):
   """Run the test suite in the Autotest lab using Skylab.
 
   Args:
@@ -1977,6 +1976,23 @@
   return android_atom
 
 
+def MarkAndroidLKGB(buildroot, android_package, android_version):
+  """Marks the given Android version as LKGB.
+
+  This is to implement Phase 2 migration of go/android-uprev-recipes. The
+  Android PFQ calls this function to update the LKGB file instead of committing
+  uprevs directly.
+  """
+  cmd = [
+      'cros_mark_android_as_stable',
+      '--update_lkgb',
+      '--android_package=%s' % android_package,
+      '--force_version=%s' % android_version,
+  ]
+
+  RunBuildScript(buildroot, cmd, chromite_cmd=True)
+
+
 def MarkChromeAsStable(buildroot,
                        tracking_branch,
                        chrome_rev,
@@ -2699,7 +2715,8 @@
     log_cmd.append('--profile=%s' % profile)
 
   if sign_types:
-    log_cmd.append('--sign-types=%s' % ' '.join(sign_types))
+    log_cmd.append('--sign-types')
+    log_cmd.extend(sign_types)
 
   if buildroot:
     log_cmd.append('--buildroot=%s' % buildroot)
@@ -3062,23 +3079,6 @@
   return tarball
 
 
-def BuildUnitTestTarball(buildroot, board, tarball_dir):
-  """Tar up the UnitTest binaries."""
-  tarball = 'unit_tests.tar'
-  tarball_path = os.path.join(tarball_dir, tarball)
-  cwd = os.path.abspath(
-      os.path.join(buildroot, 'chroot', 'build', board,
-                   constants.UNITTEST_PKG_PATH))
-  # UnitTest binaries are already compressed so just create a tar file.
-  BuildTarball(
-      buildroot, ['.'],
-      tarball_path,
-      cwd=cwd,
-      compressed=False,
-      check=False)
-  return tarball
-
-
 def BuildImageZip(archive_dir, image_dir):
   """Build image.zip in archive_dir from contents of image_dir.
 
@@ -3200,11 +3200,13 @@
   board_path = os.path.join(chroot_path, 'build', board)
   stripped_pkg_dir = os.path.join(board_path, 'stripped-packages')
   tarball_paths = []
+  strip_package_path = path_util.ToChrootPath(
+      os.path.join(constants.CHROMITE_SCRIPTS_DIR, 'strip_package'))
   for pattern in package_globs:
     packages = portage_util.FindPackageNameMatches(
         pattern, board, buildroot=buildroot)
     for cpv in packages:
-      cmd = ['strip_package', '--board', board, cpv.cpf]
+      cmd = [strip_package_path, '--board', board, cpv.cpf]
       cros_build_lib.run(cmd, cwd=buildroot, enter_chroot=True)
       # Find the stripped package.
       files = glob.glob(os.path.join(stripped_pkg_dir, cpv.cpf) + '.*')
diff --git a/cbuildbot/stages/afdo_stages.py b/cbuildbot/stages/afdo_stages.py
deleted file mode 100644
index fe318f8..0000000
--- a/cbuildbot/stages/afdo_stages.py
+++ /dev/null
@@ -1,373 +0,0 @@
-# Copyright 2014 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Module containing the AFDO stages."""
-
-import logging
-import multiprocessing
-import os
-import time
-
-from chromite.api.gen.chromite.api import toolchain_pb2
-from chromite.cbuildbot import afdo
-from chromite.cbuildbot import cbuildbot_alerts
-from chromite.cbuildbot import commands
-from chromite.cbuildbot.stages import generic_stages
-from chromite.lib import alerts
-from chromite.lib import constants
-from chromite.lib import failures_lib
-from chromite.lib import gs
-from chromite.lib import path_util
-from chromite.lib import portage_util
-
-
-class AFDODataGenerateStage(generic_stages.BoardSpecificBuilderStage,
-                            generic_stages.ForgivingBuilderStage):
-  """Stage that generates AFDO profile data from a perf profile."""
-
-  category = constants.CI_INFRA_STAGE
-
-  def _GetCurrentArch(self):
-    """Get architecture for the current board being built."""
-    return self._GetPortageEnvVar('ARCH', self._current_board)
-
-  def PerformStage(self):
-    """Collect a 'perf' profile and convert it into the AFDO format."""
-    super().PerformStage()
-
-    board = self._current_board
-    if not afdo.CanGenerateAFDOData(board):
-      logging.warning('Board %s cannot generate its own AFDO profile.', board)
-      return
-
-    arch = self._GetCurrentArch()
-    buildroot = self._build_root
-    gs_context = gs.GSContext()
-    chrome_pkg = portage_util.PortageqBestVisible(
-        constants.CHROME_CP, cwd=buildroot)
-
-    # We have a mismatch between how we version the perf.data we collect and
-    # how we version our AFDO profiles.
-    #
-    # This mismatch can cause us to generate garbage profiles, so we skip
-    # profile updates for non-r1 revisions of Chrome.
-    #
-    # Going into more detail, a perf.data file looks like:
-    # chromeos-chrome-amd64-68.0.3440.9.perf.data.bz2
-    #
-    # An AFDO profile looks like:
-    # chromeos-chrome-amd64-68.0.3440.9_rc-r1.afdo.bz2
-    #
-    # And an unstripped Chrome looks like:
-    # chromeos-chrome-amd64-68.0.3440.9_rc-r1.debug.bz2
-    #
-    # Notably, the perf.data is lacking the revision number of the Chrome it
-    # was gathered on. This is problematic, since if there's a rev bump, we'll
-    # end up using the perf.data collected on Chrome version $N-r1 with a
-    # Chrome binary built from Chrome version $N-r2, which may have an entirely
-    # different layout than Chrome version $N-r1.
-    if chrome_pkg.revision != 1:
-      logging.warning(
-          'Non-r1 version of Chrome detected; skipping AFDO generation')
-      return
-
-    # Generation of AFDO could fail for different reasons.
-    # We will ignore the failures and let the master PFQ builder try
-    # to find an older AFDO profile.
-    try:
-      if afdo.WaitForAFDOPerfData(chrome_pkg, arch, buildroot, gs_context):
-        afdo_file, uploaded_afdo = afdo.GenerateAFDOData(
-            chrome_pkg, arch, board, buildroot, gs_context)
-        assert afdo_file
-        logging.info('Generated %s AFDO profile %s', arch, afdo_file)
-
-        # If there's no new profile, merging would only be redoing the last
-        # merge and uploading nothing.
-        if not uploaded_afdo:
-          logging.info('AFDO profile already existed in GS. Quit')
-          return
-
-        merged_file, uploaded_merged = afdo.CreateAndUploadMergedAFDOProfile(
-            gs_context, buildroot, afdo_file)
-
-        if merged_file is not None:
-          logging.info('Generated %s merged AFDO profile %s', arch,
-                       merged_file)
-
-        # TODO(gbiv): once there's clarity that merged profiles are working
-        # (e.g. a week goes by with Android/Linux mostly-happily using them),
-        # we may want to turn them on for CrOS. Until then, `latest` is always
-        # the raw AFDO file.
-        if uploaded_merged and False:
-          newest_afdo_file = merged_file
-        else:
-          newest_afdo_file = afdo_file
-
-        afdo.UpdateLatestAFDOProfileInGS(chrome_pkg, arch, buildroot,
-                                         newest_afdo_file, gs_context)
-        logging.info('Pointed newest profile at %s', newest_afdo_file)
-      else:
-        raise afdo.MissingAFDOData('Could not find current "perf" profile. '
-                                   'Master PFQ builder will try to use stale '
-                                   'AFDO profile.')
-    # Will let system-exiting exceptions through.
-    except Exception:
-      cbuildbot_alerts.PrintBuildbotStepWarnings()
-      logging.warning('AFDO profile generation failed with exception ',
-                      exc_info=True)
-
-      alert_msg = ('Please triage. This will become a fatal error.\n\n'
-                   'arch=%s buildroot=%s\n\nURL=%s' %
-                   (arch, buildroot, self._run.ConstructDashboardURL()))
-      subject_msg = ('Failure in generation of AFDO Data for builder %s' %
-                     self._run.config.name)
-      alerts.SendEmailLog(subject_msg,
-                          afdo.AFDO_ALERT_RECIPIENTS,
-                          server=alerts.SmtpServer(constants.GOLO_SMTP_SERVER),
-                          message=alert_msg)
-      # Re-raise whatever exception we got here. This stage will only
-      # generate a warning but we want to make sure the warning is
-      # generated.
-      raise
-
-
-class AFDOUpdateChromeEbuildStage(generic_stages.BuilderStage):
-  """Updates the Chrome ebuild with the names of the AFDO profiles."""
-
-  category = constants.CI_INFRA_STAGE
-
-  def PerformStage(self):
-    buildroot = self._build_root
-    gs_context = gs.GSContext()
-    pkg_info = portage_util.PortageqBestVisible(
-        constants.CHROME_CP, cwd=buildroot)
-
-    # We need the name of one board that has been setup in this
-    # builder to find the Chrome ebuild. The chrome ebuild should be
-    # the same for all the boards, so just use the first one.
-    # If we don't have any boards, leave the called function to guess.
-    board = self._boards[0] if self._boards else None
-    profiles = {}
-
-    for source, getter in afdo.PROFILE_SOURCES.items():
-      profile = getter(pkg_info, source, buildroot, gs_context)
-      if not profile:
-        raise afdo.MissingAFDOData(
-            'Could not find appropriate profile for %s' % source)
-      logging.info('Found AFDO profile %s for %s', profile, source)
-      profiles[source] = profile
-
-    # Now update the Chrome ebuild file with the AFDO profiles we found
-    # for each source.
-    afdo.UpdateChromeEbuildAFDOFile(board, profiles)
-
-
-class AFDOUpdateKernelEbuildStage(generic_stages.BuilderStage):
-  """Updates the Kernel ebuild with the names of the AFDO profiles."""
-
-  category = constants.CI_INFRA_STAGE
-
-  def _WarnSheriff(self, versions):
-    subject_msg = ('Kernel AutoFDO profile too old for builder %s' %
-                   self._run.config.name)
-    alert_msg = ('AutoFDO profile too old for kernel %s. URL=%s' %
-                 (versions, self._run.ConstructDashboardURL()))
-    alerts.SendEmailLog(subject_msg, afdo.AFDO_ALERT_RECIPIENTS,
-                        server=alerts.SmtpServer(constants.GOLO_SMTP_SERVER),
-                        message=alert_msg)
-
-  def PerformStage(self):
-    version_info = self._run.GetVersionInfo()
-    build_version = [int(x) for x in version_info.VersionString().split('.')]
-    chrome_version = int(version_info.chrome_branch)
-    target_version = [chrome_version] + build_version
-    profile_versions = afdo.GetAvailableKernelProfiles()
-    candidates = sorted(afdo.FindKernelEbuilds())
-    expire_soon = set()
-    not_found = set()
-    expired = set()
-    for candidate, kver in candidates:
-      profile_version = None
-      if kver in afdo.KERNEL_SKIP_AFDO_UPDATE:
-        continue
-      if kver in profile_versions:
-        profile_version = afdo.FindLatestProfile(target_version,
-                                                 profile_versions[kver])
-      if not profile_version:
-        not_found.add(kver)
-        continue
-      if afdo.ProfileAge(profile_version) > afdo.KERNEL_ALLOWED_STALE_DAYS:
-        expired.add('%s: %s' % (kver, profile_version))
-        continue
-      if afdo.ProfileAge(profile_version) > afdo.KERNEL_WARN_STALE_DAYS:
-        expire_soon.add('%s: %s' % (kver, profile_version))
-
-      afdo.PatchKernelEbuild(candidate, profile_version)
-      # If the *-9999.ebuild is not the last entry in its directory, Manifest
-      # will contain an unused line for previous profile which is still fine.
-      if candidate.endswith('-9999.ebuild'):
-        afdo.UpdateManifest(path_util.ToChrootPath(candidate))
-    afdo.CommitIfChanged(afdo.KERNEL_EBUILD_ROOT,
-                         'Update profiles and manifests for Kernel.')
-
-    if not_found or expired:
-      raise afdo.NoValidProfileFound(
-          'Cannot find AutoFDO profiles: %s or expired: %s' %
-          (not_found, expired)
-      )
-
-    if expire_soon:
-      self._WarnSheriff(expire_soon)
-
-
-class AFDOReleaseProfileMergerStage(generic_stages.BuilderStage):
-  """Merges CWP and Benchmark AFDO profiles into 'Release' profiles."""
-
-  def PerformStage(self):
-    version_info = self._run.GetVersionInfo()
-    chrome_major_version = int(version_info.chrome_branch)
-
-    # Generate these for the last few Chrome versions. the number was
-    # arbitrarily selected, but we probably don't care after that point (and if
-    # we do, we can just run a tryjob with a locally patched value of N).
-    milestones = list(range(chrome_major_version - 2, chrome_major_version))
-    gs_context = gs.GSContext()
-
-    skipped, merge_plan = afdo.GenerateReleaseProfileMergePlan(
-        gs_context, milestones)
-    for skip in skipped:
-      logging.warning("Can't merge profile(s) for M%s at this time", skip)
-
-    if not merge_plan:
-      raise ValueError('No mergeable profiles. Fail.')
-
-    logging.info('Merge plan: %s', merge_plan)
-    merge_results = afdo.ExecuteReleaseProfileMergePlan(
-        gs_context, self._build_root, merge_plan)
-
-    assert len(merge_results) == len(merge_plan), 'Missing results?'
-    run_id = str(int(time.time()))
-    afdo.UploadReleaseProfiles(gs_context, run_id, merge_plan, merge_results)
-
-
-class GenerateAFDOArtifactStage(generic_stages.BoardSpecificBuilderStage,
-                                generic_stages.ArchivingStageMixin):
-  """Base class to generate artifacts (benchmark AFDO or orderfile)."""
-  category = constants.CI_INFRA_STAGE
-
-  def __init__(self, *args, **kwargs):
-    if 'is_orderfile' not in kwargs:
-      raise ValueError('Need to specify argument is_orderfile.')
-    self.is_orderfile = kwargs.pop('is_orderfile')
-    super().__init__(*args, **kwargs)
-    self._upload_queue = multiprocessing.Queue()
-
-  def PerformStage(self):
-    assert self.archive_path.startswith(self._build_root)
-    with self.ArtifactUploader(self._upload_queue, archive=False):
-      output_path = os.path.abspath(
-          os.path.join(self._build_root, 'chroot', self.archive_path))
-      if self.is_orderfile:
-        artifacts = commands.GenerateAFDOArtifacts(
-            self._build_root,
-            self._run.options.chrome_root,
-            self._current_board,
-            output_path, toolchain_pb2.ORDERFILE)
-      else:
-        artifacts = commands.GenerateAFDOArtifacts(
-            self._build_root,
-            self._run.options.chrome_root,
-            self._current_board,
-            output_path, toolchain_pb2.BENCHMARK_AFDO)
-      # The artifacts are uploaded to centralized GS bucket in the
-      # APIs. Only need to upload to builder's bucket now.
-      for x in artifacts:
-        self._upload_queue.put([os.path.basename(x)])
-
-class GenerateBenchmarkAFDOStage(GenerateAFDOArtifactStage):
-  """Generate benchmark AFDO artifact in the builder."""
-  def __init__(self, *args, **kwargs):
-    super().__init__(*args, is_orderfile=False, **kwargs)
-
-class GenerateChromeOrderfileStage(GenerateAFDOArtifactStage):
-  """Generate Chrome orderfile in the builder."""
-  def __init__(self, *args, **kwargs):
-    super().__init__(*args, is_orderfile=True, **kwargs)
-
-
-class VerifyAFDOArtifactStage(generic_stages.BoardSpecificBuilderStage):
-  """Base class used to verify AFDO artifacts."""
-  def __init__(self, *args, **kwargs):
-    if 'afdo_type' not in kwargs:
-      raise ValueError('Need to specify an AFDO type to update ebuild with.')
-    if 'build_api' not in kwargs:
-      raise ValueError('Need to specify a build API to execute the stage with.')
-    self.afdo_type = kwargs.pop('afdo_type')
-    self.build_api = kwargs.pop('build_api')
-    super().__init__(*args, **kwargs)
-
-  def PerformStage(self):
-    status = commands.VerifyAFDOArtifacts(
-        self._build_root,
-        self._current_board,
-        self.afdo_type,
-        self.build_api)
-
-    if not status:
-      raise failures_lib.StepFailure(
-          'Failed when running the build API.')
-
-class OrderfileUpdateChromeEbuildStage(VerifyAFDOArtifactStage):
-  """Updates the Chrome ebuild with the most recent unvetted orderfile."""
-
-  def __init__(self, *args, **kwargs):
-    super().__init__(
-        *args, afdo_type=toolchain_pb2.ORDERFILE,
-        build_api='chromite.api.ToolchainService/UpdateEbuildWithAFDOArtifacts',
-        **kwargs)
-
-
-class KernelAFDOUpdateEbuildStage(VerifyAFDOArtifactStage):
-  """Updates kernel ebuilds with latest unvetted AFDO profiles."""
-  def __init__(self, *args, **kwargs):
-    super().__init__(
-        *args, afdo_type=toolchain_pb2.KERNEL_AFDO,
-        build_api='chromite.api.ToolchainService/UpdateEbuildWithAFDOArtifacts',
-        **kwargs)
-
-
-class ChromeAFDOUpdateEbuildStage(VerifyAFDOArtifactStage):
-  """Updates Chrome ebuilds with latest unvetted AFDO profiles."""
-  def __init__(self, *args, **kwargs):
-    super().__init__(
-        *args, afdo_type=toolchain_pb2.CHROME_AFDO,
-        build_api='chromite.api.ToolchainService/UpdateEbuildWithAFDOArtifacts',
-        **kwargs)
-
-
-class UploadVettedOrderfileStage(VerifyAFDOArtifactStage):
-  """Upload a vetted orderfile to GS bucket."""
-  def __init__(self, *args, **kwargs):
-    super().__init__(
-        *args, afdo_type=toolchain_pb2.ORDERFILE,
-        build_api='chromite.api.ToolchainService/UploadVettedAFDOArtifacts',
-        **kwargs)
-
-
-class UploadVettedKernelAFDOStage(VerifyAFDOArtifactStage):
-  """Upload latest kernel AFDO profiles."""
-  def __init__(self, *args, **kwargs):
-    super().__init__(
-        *args, afdo_type=toolchain_pb2.KERNEL_AFDO,
-        build_api='chromite.api.ToolchainService/UploadVettedAFDOArtifacts',
-        **kwargs)
-
-
-class UploadVettedChromeAFDOStage(VerifyAFDOArtifactStage):
-  """Upload latest Chrome AFDO profiles."""
-  def __init__(self, *args, **kwargs):
-    super().__init__(
-        *args, afdo_type=toolchain_pb2.CHROME_AFDO,
-        build_api='chromite.api.ToolchainService/UploadVettedAFDOArtifacts',
-        **kwargs)
diff --git a/cbuildbot/stages/afdo_stages_unittest.py b/cbuildbot/stages/afdo_stages_unittest.py
deleted file mode 100644
index 76b35ba..0000000
--- a/cbuildbot/stages/afdo_stages_unittest.py
+++ /dev/null
@@ -1,259 +0,0 @@
-# Copyright 2018 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Unittests for updating Chrome ebuild stages."""
-
-import os
-from unittest import mock
-
-from chromite.api.gen.chromite.api import toolchain_pb2
-from chromite.cbuildbot import afdo
-from chromite.cbuildbot import cbuildbot_unittest
-from chromite.cbuildbot import commands
-from chromite.cbuildbot.stages import afdo_stages
-from chromite.cbuildbot.stages import generic_stages_unittest
-from chromite.lib import alerts
-from chromite.lib import cros_test_lib
-from chromite.lib import gs
-from chromite.lib import osutils
-from chromite.lib import portage_util
-from chromite.lib.buildstore import FakeBuildStore
-from chromite.lib.parser import package_info
-
-
-def _GenerateAFDOGenerateTest(chrome_version_str, expected_to_generate_profile,
-                              test_name):
-
-  class Test(generic_stages_unittest.AbstractStageTestCase):
-    """Test that we don't update non-r1 AFDO profiles"""
-
-    def setUp(self):
-      self.PatchObject(afdo, 'CanGenerateAFDOData', lambda _: True)
-      chrome_version = package_info.parse(chrome_version_str)
-      self.PatchObject(portage_util, 'PortageqBestVisible',
-                       lambda *_, **_2: chrome_version)
-      self.wait_for_data = self.PatchObject(
-          afdo, 'WaitForAFDOPerfData', autospec=True, wraps=lambda *_: True)
-
-      afdo_path = '/does/not/exist/afdo.prof'
-      self.generate_afdo_data = self.PatchObject(
-          afdo, 'GenerateAFDOData', autospec=True, wraps=lambda *_: afdo_path)
-
-      self.PatchObject(afdo_stages.AFDODataGenerateStage, '_GetCurrentArch',
-                       lambda *_: 'some_arch')
-      self.PatchObject(alerts, 'SendEmailLog')
-      self._Prepare()
-      self.buildstore = FakeBuildStore()
-
-    def ConstructStage(self):
-      return afdo_stages.AFDODataGenerateStage(self._run, self.buildstore,
-                                               'some_board')
-
-    def testAFDOUpdateChromeEbuildStage(self):
-      self.RunStage()
-      if expected_to_generate_profile:
-        self.assertTrue(self.wait_for_data.called)
-        self.assertTrue(self.generate_afdo_data.called)
-      else:
-        self.assertFalse(self.wait_for_data.called)
-        self.assertFalse(self.generate_afdo_data.called)
-
-  Test.__name__ = test_name
-  return Test
-
-
-def _MakeChromeVersionWithRev(rev):
-  return 'chromeos-chrome/chromeos-chrome-68.0.3436.0_rc-r%d' % rev
-
-
-R1Test = _GenerateAFDOGenerateTest(
-    chrome_version_str=_MakeChromeVersionWithRev(1),
-    expected_to_generate_profile=True,
-    test_name='AFDODataGenerateStageUpdatesR1ProfilesTest',
-)
-
-R2Test = _GenerateAFDOGenerateTest(
-    chrome_version_str=_MakeChromeVersionWithRev(2),
-    expected_to_generate_profile=False,
-    test_name='AFDODataGenerateStageDoesntUpdateNonR1ProfilesTest',
-)
-
-
-class UpdateChromeEbuildTest(generic_stages_unittest.AbstractStageTestCase):
-  """Test updating Chrome ebuild files"""
-
-  def setUp(self):
-    # Intercept afdo.UpdateChromeEbuildAFDOFile so that we can check how it is
-    # called.
-    self.patch_mock = self.PatchObject(
-        afdo, 'UpdateChromeEbuildAFDOFile', autospec=True)
-    # Don't care the return value of portage_util.PortageqBestVisible
-    self.PatchObject(portage_util, 'PortageqBestVisible')
-    # Don't care the return value of gs.GSContext
-    self.PatchObject(gs, 'GSContext')
-    # Don't call the getters; Use mock responses instead.
-    self.PatchDict(
-        afdo.PROFILE_SOURCES, {
-            'benchmark': lambda *_: 'benchmark.afdo',
-            'silvermont': lambda *_: 'silvermont.afdo'
-        },
-        clear=True)
-    self._Prepare()
-    self.buildstore = FakeBuildStore()
-
-  def ConstructStage(self):
-    return afdo_stages.AFDOUpdateChromeEbuildStage(self._run, self.buildstore)
-
-  def testAFDOUpdateChromeEbuildStage(self):
-    self.RunStage()
-
-    # afdo.UpdateChromeEbuildAFDOFile should be called with the mock responses
-    # from profile source specific query.
-    self.patch_mock.assert_called_with('amd64-generic', {
-        'benchmark': 'benchmark.afdo',
-        'silvermont': 'silvermont.afdo'
-    })
-
-
-class GenerateAFDOArtifactStageTests(
-    generic_stages_unittest.AbstractStageTestCase,
-    cbuildbot_unittest.SimpleBuilderTestCase):
-  """Test class of GenerateAFDOArtifactStage."""
-
-  RELEASE_TAG = ''
-
-  # pylint: disable=protected-access
-  def setUp(self):
-    self._Prepare()
-    self.rc_mock = self.StartPatcher(cros_test_lib.RunCommandMock())
-    self.rc_mock.SetDefaultCmdResult()
-    self.buildstore = FakeBuildStore()
-    # Prepare the directories
-    chroot_tmp = os.path.join(self.build_root, 'chroot', 'tmp')
-    osutils.SafeMakedirs(chroot_tmp)
-
-  # pylint: disable=arguments-differ
-  def ConstructStage(self, is_afdo):
-    self._run.GetArchive().SetupArchivePath()
-    if is_afdo:
-      return afdo_stages.GenerateBenchmarkAFDOStage(
-          self._run, self.buildstore, self._current_board)
-
-    return afdo_stages.GenerateChromeOrderfileStage(
-        self._run, self.buildstore, self._current_board)
-
-  def testRunSuccess(self):
-    """Test the main function runs without problems."""
-    for is_afdo in [True, False]:
-      stage = self.ConstructStage(is_afdo)
-      artifacts = ['tarball.1.xz', '/path/to/tarball.2.xz']
-      self.PatchObject(stage, 'ArtifactUploader')
-      mock_generate = self.PatchObject(
-          commands, 'GenerateAFDOArtifacts',
-          return_value=artifacts)
-      mock_put = self.PatchObject(stage._upload_queue, 'put')
-      stage.PerformStage()
-      output_path = os.path.abspath(
-          os.path.join(self.build_root, 'chroot',
-                       stage.archive_path))
-      if is_afdo:
-        target = toolchain_pb2.BENCHMARK_AFDO
-      else:
-        target = toolchain_pb2.ORDERFILE
-      mock_generate.assert_called_once_with(
-          self.build_root, None, self._current_board,
-          output_path, target)
-      calls = [mock.call([os.path.basename(x)]) for x in artifacts]
-      mock_put.assert_has_calls(calls)
-
-
-class VerifyAFDOArtifactStageTests(
-    generic_stages_unittest.AbstractStageTestCase,
-    cbuildbot_unittest.SimpleBuilderTestCase):
-  """Test class of VerifyAFDOArtifactStage."""
-  RELEASE_TAG = ''
-
-  # pylint: disable=protected-access
-  def setUp(self):
-    self._Prepare()
-    self.rc_mock = self.StartPatcher(cros_test_lib.RunCommandMock())
-    self.rc_mock.SetDefaultCmdResult()
-    self.buildstore = FakeBuildStore()
-
-  # pylint: disable=arguments-differ
-  def ConstructStage(self, artifact_type, stage_type):
-    self._run.GetArchive().SetupArchivePath()
-    if artifact_type == 'orderfile':
-      if stage_type == 'update':
-        return afdo_stages.OrderfileUpdateChromeEbuildStage(
-            self._run, self.buildstore, self._current_board)
-
-      return afdo_stages.UploadVettedOrderfileStage(
-          self._run, self.buildstore, self._current_board)
-
-    if artifact_type == 'kernel_afdo':
-      if stage_type == 'update':
-        return afdo_stages.KernelAFDOUpdateEbuildStage(
-            self._run, self.buildstore, self._current_board)
-
-      return afdo_stages.UploadVettedKernelAFDOStage(
-          self._run, self.buildstore, self._current_board)
-
-    if stage_type == 'update':
-      return afdo_stages.ChromeAFDOUpdateEbuildStage(
-          self._run, self.buildstore, self._current_board)
-
-    return afdo_stages.UploadVettedChromeAFDOStage(
-        self._run, self.buildstore, self._current_board)
-
-  def testOrderfileUpdateSuccess(
-      self, artifact_type='orderfile', stage_type='update'):
-    """Test update ebuild with orderfile call correctly.
-
-    Parameterize the two arguments for testing different stage types.
-    """
-    stage = self.ConstructStage(artifact_type, stage_type)
-    mock_verify = self.PatchObject(
-        commands, 'VerifyAFDOArtifacts', return_value=True)
-
-    stage.PerformStage()
-
-    # Verify wrapper function is called correctly.
-    if artifact_type == 'orderfile':
-      target = toolchain_pb2.ORDERFILE
-    elif artifact_type == 'kernel_afdo':
-      target = toolchain_pb2.KERNEL_AFDO
-    else:
-      target = toolchain_pb2.CHROME_AFDO
-
-    if stage_type == 'update':
-      build_api = 'chromite.api.ToolchainService/UpdateEbuildWithAFDOArtifacts'
-    else:
-      build_api = 'chromite.api.ToolchainService/UploadVettedAFDOArtifacts'
-
-    mock_verify.assert_called_once_with(
-        self.build_root, self._current_board,
-        target, build_api)
-
-  def testOrderfileUploadSuccess(self):
-    """Test upload vetted orderfile call correctly."""
-    self.testOrderfileUpdateSuccess(stage_type='upload')
-
-  def testKernelAFDOUpdateSuccess(self):
-    """Test update ebuild with kernel AFDO call correctly."""
-    self.testOrderfileUpdateSuccess(artifact_type='kernel_afdo')
-
-  def testKernelAFDOUploadSuccess(self):
-    """Test upload vetted kernel AFDO call correctly."""
-    self.testOrderfileUpdateSuccess(artifact_type='kernel_afdo',
-                                    stage_type='upload')
-
-  def testChromeAFDOUpdateSuccess(self):
-    """Test update ebuild with Chrome AFDO call correctly."""
-    self.testOrderfileUpdateSuccess(artifact_type='chrome_afdo')
-
-  def testChromeAFDOUploadSuccess(self):
-    """Test upload vetted Chrome AFDO call correctly."""
-    self.testOrderfileUpdateSuccess(artifact_type='chrome_afdo',
-                                    stage_type='upload')
diff --git a/cbuildbot/stages/android_stages.py b/cbuildbot/stages/android_stages.py
index 0da5d46..c7ee549 100644
--- a/cbuildbot/stages/android_stages.py
+++ b/cbuildbot/stages/android_stages.py
@@ -63,6 +63,15 @@
     logging.info('Android branch: %s', android_build_branch)
     logging.info('Android version: %s', android_version or 'LATEST')
 
+    if self._run.config.master and self._run.config.android_update_lkgb:
+      # If android_update_lkgb is set, the master builder publishes a LKGB
+      # update instead of an ebuild uprev. The LKGB update will in turn trigger
+      # the PUpr generator to generate actual Android uprev CLs.
+      commands.MarkAndroidLKGB(buildroot=self._build_root,
+                               android_package=android_package,
+                               android_version=android_version)
+      return
+
     try:
       android_atom_to_build = commands.MarkAndroidAsStable(
           buildroot=self._build_root,
diff --git a/cbuildbot/stages/artifact_stages.py b/cbuildbot/stages/artifact_stages.py
index 51dd185..e7a9645 100644
--- a/cbuildbot/stages/artifact_stages.py
+++ b/cbuildbot/stages/artifact_stages.py
@@ -337,7 +337,7 @@
         if config.base_is_recovery:
           recovery_image_path = os.path.join(image_dir,
                                              constants.RECOVERY_IMAGE_BIN)
-          logging.info('Copying the base image to: %s',  recovery_image_path)
+          logging.info('Copying the base image to: %s', recovery_image_path)
           shutil.copyfile(base_image_path, recovery_image_path)
         else:
           logging.info('Running commands.BuildRecoveryImage')
@@ -356,8 +356,11 @@
         self._recovery_image_status_queue.put(False)
 
       if config['images']:
-        steps = [
-            BuildAndArchiveFactoryImages,
+        if self._run.HasUseFlag(board, 'no_factory_flow'):
+          steps = []
+        else:
+          steps = [BuildAndArchiveFactoryImages]
+        steps += [
             ArchiveLicenseFile,
             ArchiveHWQual,
             ArchiveStandaloneArtifacts,
diff --git a/cbuildbot/stages/branch_archive_stages_unittest.py b/cbuildbot/stages/branch_archive_stages_unittest.py
index 9cbe68c..0268889 100644
--- a/cbuildbot/stages/branch_archive_stages_unittest.py
+++ b/cbuildbot/stages/branch_archive_stages_unittest.py
@@ -103,7 +103,7 @@
             self.workspace,
             'board',
             extra_env={
-                'USE': '-cros-debug chrome_internal',
+                'USE': '-cros-debug chrome_internal thinlto',
             }),
     ])
 
@@ -216,7 +216,7 @@
             self.workspace,
             'board',
             extra_env={
-                'USE': '-cros-debug chrome_internal',
+                'USE': '-cros-debug chrome_internal thinlto',
             }),
     ])
 
diff --git a/cbuildbot/stages/build_stages.py b/cbuildbot/stages/build_stages.py
index ef414fc..5d77272 100644
--- a/cbuildbot/stages/build_stages.py
+++ b/cbuildbot/stages/build_stages.py
@@ -404,10 +404,12 @@
                                 self._run.options.preserve_paths)
     else:
       tasks = [
-          self._BuildRootGitCleanup, self._WipeOldOutput,
+          self._WipeOldOutput,
           self._DeleteArchivedTrybotImages, self._DeleteArchivedPerfResults,
           self._DeleteAutotestSitePackages
       ]
+      if not os.path.ismount(self._build_root):
+        tasks.insert(0, self._BuildRootGitCleanup)
       if self._run.options.chrome_root:
         tasks.append(self._DeleteChromeBuildOutput)
       if delete_chroot:
diff --git a/cbuildbot/stages/build_stages_unittest.py b/cbuildbot/stages/build_stages_unittest.py
index ed87385..0282f89 100644
--- a/cbuildbot/stages/build_stages_unittest.py
+++ b/cbuildbot/stages/build_stages_unittest.py
@@ -607,7 +607,7 @@
 class CleanUpStageTest(generic_stages_unittest.StageTestCase):
   """Test CleanUpStage."""
 
-  BOT_ID = 'amd64-generic-incremental'
+  BOT_ID = 'amd64-generic-asan'
 
   def setUp(self):
     self.fake_db = fake_cidb.FakeCIDBConnection()
diff --git a/cbuildbot/stages/completion_stages_unittest.py b/cbuildbot/stages/completion_stages_unittest.py
index 7b73686..f18920b 100644
--- a/cbuildbot/stages/completion_stages_unittest.py
+++ b/cbuildbot/stages/completion_stages_unittest.py
@@ -229,7 +229,7 @@
 class PublishUprevChangesStageTest(
     generic_stages_unittest.AbstractStageTestCase):
   """Tests for the PublishUprevChanges stage."""
-  BOT_ID = 'master-vmt-android-pfq'
+  BOT_ID = 'hatch-android-rvc-pre-flight-branch'
 
   def setUp(self):
     self.PatchObject(completion_stages.PublishUprevChangesStage,
@@ -318,20 +318,6 @@
     # No stage information for slave_c
     self.assertFalse(stage.CheckSlaveUploadPrebuiltsTest())
 
-  def testAndroidPush(self):
-    """Test values for PublishUprevChanges with Android PFQ."""
-    self._Prepare(
-        bot_id=constants.PI_ANDROID_PFQ_MASTER,
-        extra_config={'push_overlays': constants.PUBLIC_OVERLAYS},
-        extra_cmd_args=['--android_rev', constants.ANDROID_REV_LATEST])
-    self._run.options.prebuilts = True
-    self.RunStage()
-    self.push_mock.assert_called_once_with(
-        self.build_root, overlay_type='public', dryrun=False)
-    self.assertTrue(self._run.attrs.metadata.GetValue('UprevvedAndroid'))
-    metadata_dict = self._run.attrs.metadata.GetDict()
-    self.assertNotIn('UprevvedChrome', metadata_dict)
-
   def testPerformStageOnChromePFQ(self):
     """Test PerformStage on ChromePFQ."""
     stage = self.ConstructStage()
diff --git a/cbuildbot/stages/generic_stages_unittest.py b/cbuildbot/stages/generic_stages_unittest.py
index c55df0a..878bd4e 100644
--- a/cbuildbot/stages/generic_stages_unittest.py
+++ b/cbuildbot/stages/generic_stages_unittest.py
@@ -665,7 +665,7 @@
   # pylint: disable=abstract-method
 
   FULL_BOT_ID = 'amd64-generic-full'
-  BIN_BOT_ID = 'amd64-generic-incremental'
+  BIN_BOT_ID = 'amd64-generic-asan'
 
   def _PrepareFull(self, **kwargs):
     self._Prepare(self.FULL_BOT_ID, **kwargs)
diff --git a/cbuildbot/stages/sdk_stages.py b/cbuildbot/stages/sdk_stages.py
index eaa4305..5eb4b48 100644
--- a/cbuildbot/stages/sdk_stages.py
+++ b/cbuildbot/stages/sdk_stages.py
@@ -8,6 +8,7 @@
 import json
 import logging
 import os
+import re
 
 from chromite.cbuildbot import cbuildbot_alerts
 from chromite.cbuildbot import commands
@@ -140,6 +141,9 @@
     board_location = os.path.join(chroot_location, 'build/amd64-host')
     manifest_location = tarball_location + '.Manifest'
 
+    # Cleanup etc/make.conf.board_setup for use in SDK.
+    self.CleanupMakeConfBoardSetup(board_location)
+
     # Create a tarball of the latest SDK.
     CreateTarball(board_location, tarball_location,
                   exclude_paths=PACKAGE_EXCLUDED_PATHS)
@@ -212,6 +216,19 @@
                          self.ConstructDashboardURL(), self.sdk_version,
                          self._run.bot_id)
 
+  def CleanupMakeConfBoardSetup(self, board_location):
+    """Cleanup etc/make.conf.board_setup to be usable in the SDK"""
+    board_setup = os.path.join(board_location, 'etc/make.conf.board_setup')
+    lines = osutils.ReadFile(board_setup).splitlines()
+
+    to_remove = re.compile(r'^(ROOT|PKG_CONFIG)=')
+    lines = [x for x in lines if not to_remove.match(x)]
+    data = '\n'.join(lines) + '\n'
+    if '/build/' in data:
+      logging.error('%s content:\n%s', board_setup, data)
+      raise ValueError('/build/ paths must be cleaned from make.conf')
+    osutils.WriteFile(board_setup, data, sudo=True)
+
 
 class SDKPackageToolchainOverlaysStage(generic_stages.BuilderStage):
   """Stage that creates and packages per-board toolchain overlays."""
diff --git a/cbuildbot/stages/sdk_stages_unittest.py b/cbuildbot/stages/sdk_stages_unittest.py
index 4f3ac65..36673b6 100644
--- a/cbuildbot/stages/sdk_stages_unittest.py
+++ b/cbuildbot/stages/sdk_stages_unittest.py
@@ -75,6 +75,8 @@
     self.buildstore = FakeBuildStore()
     # Replace sudo_run, since we don't care about sudo.
     self.PatchObject(cros_build_lib, 'sudo_run', wraps=cros_build_lib.run)
+    # Don't run CleanupMakeConfBoardSetup as it needs sudo_run.
+    self.PatchObject(sdk_stages.SDKPackageStage, 'CleanupMakeConfBoardSetup')
     self.uploadartifact_mock = self.PatchObject(
         generic_stages.ArchivingStageMixin, 'UploadArtifact')
     # Prepare a fake chroot.
diff --git a/cbuildbot/stages/sync_stages_unittest.py b/cbuildbot/stages/sync_stages_unittest.py
index c8ecdb9..98be140 100644
--- a/cbuildbot/stages/sync_stages_unittest.py
+++ b/cbuildbot/stages/sync_stages_unittest.py
@@ -225,14 +225,14 @@
 class MasterSlaveLKGMSyncTest(generic_stages_unittest.StageTestCase):
   """Unit tests for MasterSlaveLKGMSyncStage"""
 
-  BOT_ID = constants.VMT_ANDROID_PFQ_MASTER
+  BOT_ID = 'hatch-android-rvc-pre-flight-branch'
 
   def setUp(self):
     """Setup"""
     self.source_repo = 'ssh://source/repo'
     self.manifest_version_url = 'fake manifest url'
     self.branch = 'master'
-    self.build_name = 'master-vmt-android-pfq'
+    self.build_name = self.BOT_ID
     self.incr_type = 'branch'
     self.next_version = 'next_version'
     self.sync_stage = None
diff --git a/cbuildbot/stages/test_stages.py b/cbuildbot/stages/test_stages.py
index 870432b..7acd66e 100644
--- a/cbuildbot/stages/test_stages.py
+++ b/cbuildbot/stages/test_stages.py
@@ -8,7 +8,6 @@
 import logging
 import os
 
-from chromite.cbuildbot import afdo
 from chromite.cbuildbot import cbuildbot_alerts
 from chromite.cbuildbot import cbuildbot_run
 from chromite.cbuildbot import commands
@@ -18,12 +17,10 @@
 from chromite.lib import constants
 from chromite.lib import cros_build_lib
 from chromite.lib import failures_lib
-from chromite.lib import gs
 from chromite.lib import image_test_lib
 from chromite.lib import osutils
 from chromite.lib import parallel
 from chromite.lib import perf_uploader
-from chromite.lib import portage_util
 from chromite.lib import timeout_util
 
 
@@ -69,10 +66,6 @@
           blacklist=self._run.config.unittest_blacklist,
           extra_env=extra_env,
           build_stage=self._run.config.build_packages)
-    # Package UnitTest binaries.
-    tarball = commands.BuildUnitTestTarball(
-        self._build_root, self._current_board, self.archive_path)
-    self.UploadArtifact(tarball, archive=False)
 
 
 class HWTestDUTOverride:
@@ -185,22 +178,6 @@
       return not builder_run.options.debug
 
   def PerformStage(self):
-    if self.suite_config.suite == constants.HWTEST_AFDO_SUITE:
-      arch = self._GetPortageEnvVar('ARCH', self._current_board)
-      pkg_info = portage_util.PortageqBestVisible(
-          constants.CHROME_CP, cwd=self._build_root)
-      # For async AFDO builders, need to skip this check because it's checking
-      # a different bucket for PFQ AFDO. Also for async AFDO builders, no need
-      # to check here because there's an earlier check to avoid generating
-      # AFDO for the same version.
-      if (not self._run.config.afdo_generate_async and
-          afdo.CheckAFDOPerfData(pkg_info, arch, gs.GSContext())):
-        logging.info(
-            'AFDO profile already generated for arch %s '
-            'and Chrome %s. Not generating it again', arch,
-            pkg_info.version.split('_')[0])
-        return
-
     build = '/'.join([self._bot_id, self.version])
 
     skip_duts_check = False
@@ -488,13 +465,13 @@
     """All models to run tests against."""
     if self._run.options.hwtest_dut_override:
       return [config_lib.ModelTestConfig(
-        self._run.options.hwtest_dut_override.model, None)]
+          self._run.options.hwtest_dut_override.model, None)]
 
     if self._run.config.models:
       return self._run.config.models
 
     return [config_lib.ModelTestConfig(
-      None, config_lib.GetNonUniBuildLabBoardName(self._current_board))]
+        None, config_lib.GetNonUniBuildLabBoardName(self._current_board))]
 
 
   def WaitUntilReady(self):
diff --git a/cbuildbot/stages/test_stages_unittest.py b/cbuildbot/stages/test_stages_unittest.py
index 58e05f2..2232525 100644
--- a/cbuildbot/stages/test_stages_unittest.py
+++ b/cbuildbot/stages/test_stages_unittest.py
@@ -44,8 +44,6 @@
 
   def setUp(self):
     self.rununittests_mock = self.PatchObject(commands, 'RunUnitTests')
-    self.buildunittests_mock = self.PatchObject(
-        commands, 'BuildUnitTestTarball', return_value='unit_tests.tar')
     self.uploadartifact_mock = self.PatchObject(
         generic_stages.ArchivingStageMixin, 'UploadArtifact')
     self.image_dir = os.path.join(
@@ -74,11 +72,6 @@
         blacklist=[],
         extra_env=mock.ANY,
         build_stage=True)
-    self.buildunittests_mock.assert_called_once_with(
-        self.build_root, self._current_board,
-        self._run.GetArchive().archive_path)
-    self.uploadartifact_mock.assert_called_once_with(
-        'unit_tests.tar', archive=False)
 
 
 class HWTestStageTest(generic_stages_unittest.AbstractStageTestCase,
@@ -463,17 +456,20 @@
     """Test TestPlanStage.ModelsToTest with a DUT model override."""
     builder_run = self._initConfig('octopus-release')
     builder_run.options.hwtest_dut_override = test_stages.HWTestDUTOverride(
-      'bar-board', 'bar-model', 'bar-pool')
+        'bar-board', 'bar-model', 'bar-pool')
     stage = test_stages.TestPlanStage(builder_run, self.buildstore, 'octopus')
     models_to_test = stage.ModelsToTest()
     self.assertEqual([model.name for model in models_to_test], ['bar-model'])
 
 
+  @pytest.mark.skip(reason='Test relies on external state: b/215089089')
   def testModelsToTestWithoutDUTOverride(self):
     """Test TestPlanStage.ModelsToTest without a DUT model override."""
     builder_run = self._initConfig('octopus-release')
     stage = test_stages.TestPlanStage(builder_run, self.buildstore, 'octopus')
     models_to_test = stage.ModelsToTest()
-    # Too many models to list them all; just check the first few.
-    self.assertEqual([model.name for model in models_to_test[0:3]],
-                     ['ampton', 'apel', 'apel-e'])
+    # Too many models to list them all; just check a subset
+    model_names = [m.name for m in models_to_test]
+    known_models = ['phaser', 'phaser360', 'sparky']
+    for model in known_models:
+      self.assertIn(model, model_names)
diff --git a/cbuildbot/stages/workspace_stages_unittest.py b/cbuildbot/stages/workspace_stages_unittest.py
index d87c2fc..47af13b 100644
--- a/cbuildbot/stages/workspace_stages_unittest.py
+++ b/cbuildbot/stages/workspace_stages_unittest.py
@@ -417,7 +417,7 @@
             '--cache-dir', '/cache',
         ],
         extra_env={
-            'USE': '-cros-debug chrome_internal',
+            'USE': '-cros-debug chrome_internal thinlto',
         },
         cwd=self.workspace,
     )
@@ -440,7 +440,7 @@
             '--chrome_root', '/chrome',
         ],
         extra_env={
-            'USE': '-cros-debug chrome_internal',
+            'USE': '-cros-debug chrome_internal thinlto',
             'CHROME_ORIGIN': 'LOCAL_SOURCE',
         },
         cwd=self.workspace,
@@ -469,7 +469,7 @@
         enter_chroot=True,
         chroot_args=['--cache-dir', '/cache'],
         extra_env={
-            'USE': '-cros-debug chrome_internal',
+            'USE': '-cros-debug chrome_internal thinlto',
             'FEATURES': ' -separatedebug splitdebug',
         },
         cwd=self.workspace,
@@ -492,7 +492,7 @@
         extra_env={
             'CHROME_ORIGIN': 'LOCAL_SOURCE',
             'FEATURES': ' -separatedebug splitdebug',
-            'USE': '-cros-debug chrome_internal',
+            'USE': '-cros-debug chrome_internal thinlto',
         },
         cwd=self.workspace,
     )
@@ -534,7 +534,7 @@
         enter_chroot=True,
         chroot_args=['--cache-dir', '/cache'],
         extra_env={
-            'USE': '-cros-debug chrome_internal',
+            'USE': '-cros-debug chrome_internal thinlto',
         },
         cwd=self.workspace,
     )
@@ -561,7 +561,7 @@
         enter_chroot=True,
         chroot_args=['--cache-dir', '/cache'],
         extra_env={
-            'USE': '-cros-debug chrome_internal',
+            'USE': '-cros-debug chrome_internal thinlto',
         },
         cwd=self.workspace,
     )
@@ -588,7 +588,7 @@
         enter_chroot=True,
         chroot_args=['--cache-dir', '/cache', '--chrome_root', '/chrome'],
         extra_env={
-            'USE': '-cros-debug chrome_internal',
+            'USE': '-cros-debug chrome_internal thinlto',
             'CHROME_ORIGIN': 'LOCAL_SOURCE',
         },
         cwd=self.workspace,
@@ -616,7 +616,7 @@
         enter_chroot=True,
         chroot_args=['--cache-dir', '/cache', '--chrome_root', '/chrome'],
         extra_env={
-            'USE': '-cros-debug chrome_internal',
+            'USE': '-cros-debug chrome_internal thinlto',
             'CHROME_ORIGIN': 'LOCAL_SOURCE',
         },
         cwd=self.workspace,
@@ -657,7 +657,7 @@
         enter_chroot=True,
         chroot_args=['--cache-dir', '/cache', '--chrome_root', '/chrome'],
         extra_env={
-            'USE': u'-cros-debug chrome_internal',
+            'USE': u'-cros-debug chrome_internal thinlto',
             'CHROME_ORIGIN': 'LOCAL_SOURCE',
         },
         cwd=self.workspace,
@@ -701,7 +701,7 @@
                  '--board=board', '--jobs=10'],
                 enter_chroot=True,
                 chroot_args=['--cache-dir', '/cache'],
-                extra_env={'USE': '-cros-debug chrome_internal'},
+                extra_env={'USE': '-cros-debug chrome_internal thinlto'},
                 cwd=self.workspace,
             ),
         ]
@@ -738,7 +738,7 @@
         enter_chroot=True,
         chroot_args=['--cache-dir', '/cache'],
         extra_env={
-            'USE': '-cros-debug chrome_internal',
+            'USE': '-cros-debug chrome_internal thinlto',
         },
         cwd=self.workspace,
     )
@@ -768,7 +768,7 @@
         enter_chroot=True,
         chroot_args=['--cache-dir', '/cache'],
         extra_env={
-            'USE': '-cros-debug chrome_internal',
+            'USE': '-cros-debug chrome_internal thinlto',
         },
         cwd=self.workspace,
     )
@@ -813,7 +813,7 @@
         enter_chroot=True,
         chroot_args=['--cache-dir', '/cache'],
         extra_env={
-            'USE': '-cros-debug chrome_internal',
+            'USE': '-cros-debug chrome_internal thinlto',
         },
         cwd=self.workspace)
 
diff --git a/cidb/migrations/00025_alter_build_table_add_summary.sql b/cidb/migrations/00025_alter_build_table_add_summary.sql
index 0ce91db..34a82db 100644
--- a/cidb/migrations/00025_alter_build_table_add_summary.sql
+++ b/cidb/migrations/00025_alter_build_table_add_summary.sql
@@ -1,6 +1,6 @@
 -- The summary field contains an overall human readable summary of the build.
--- The master builders summarize failures from all their slaves.
--- slaves summarize only their own failure.
+-- The main builders summarize failures from all their nodes.
+-- nodes summarize only their own failure.
 ALTER TABLE buildTable
   ADD COLUMN summary varchar(1024) DEFAULT NULL;
 
diff --git a/cli/README.md b/cli/README.md
index 10e7da6..d3fa781 100644
--- a/cli/README.md
+++ b/cli/README.md
@@ -11,7 +11,7 @@
 
 The command class's implementation _must_:
 *   Be a subclass of `cli.command.Command`
-*   Have a `@command.CommandDecorator('command-name')` decorator on the class
+*   Have a `@command.command_decorator('command-name')` decorator on the class
 *   Define an `EPILOG` class constant
 *   Implement the `@classmethod` `AddParser(cls, parser)`
 *   Implement `Run(self)`
diff --git a/cli/command.py b/cli/command.py
index 554ab32..5f91fdb 100644
--- a/cli/command.py
+++ b/cli/command.py
@@ -6,8 +6,8 @@
 
 This module contains two important definitions used by all commands:
   CliCommand: The parent class of all CLI commands.
-  CommandDecorator: Decorator that must be used to ensure that the command shows
-    up in |_commands| and is discoverable.
+  command_decorator: Decorator that must be used to ensure that the command
+    shows up in |_commands| and is discoverable.
 
 Commands can be either imported directly or looked up using this module's
 ListCommands() function.
@@ -45,7 +45,7 @@
   """Directly import the specified subcommand.
 
   This method imports the module which must contain the single subcommand.  When
-  the module is loaded, the declared command (those that use CommandDecorator)
+  the module is loaded, the declared command (those that use command_decorator)
   will automatically get added to |_commands|.
 
   Args:
@@ -85,10 +85,10 @@
   """Error that occurs when command class fails sanity checks."""
 
 
-def CommandDecorator(command_name):
+def command_decorator(name):
   """Decorator that sanity checks and adds class to list of usable commands."""
 
-  def InnerCommandDecorator(original_class):
+  def inner_decorator(original_class):
     """Inner Decorator that actually wraps the class."""
     if not hasattr(original_class, '__doc__'):
       raise InvalidCommandError('All handlers must have docstrings: %s' %
@@ -98,12 +98,12 @@
       raise InvalidCommandError('All Commands must derive from CliCommand: %s' %
                                 original_class)
 
-    _commands[command_name] = original_class
-    original_class.command_name = command_name
+    _commands[name] = original_class
+    original_class.name = name
 
     return original_class
 
-  return InnerCommandDecorator
+  return inner_decorator
 
 
 class CliCommand(object):
@@ -111,8 +111,8 @@
 
   This class provides the abstract interface for all CLI commands. When
   designing a new command, you must sub-class from this class and use the
-  CommandDecorator decorator. You must specify a class docstring as that will be
-  used as the usage for the sub-command.
+  command_decorator decorator. You must specify a class docstring as that will
+  be used as the usage for the sub-command.
 
   In addition your command should implement AddParser which is passed in a
   parser that you can add your own custom arguments. See argparse for more
@@ -130,6 +130,12 @@
     parser.set_defaults(command_class=cls)
 
   @classmethod
+  def ProcessOptions(cls,
+                     parser: commandline.ArgumentParser,
+                     options: commandline.ArgumentNamespace) -> None:
+    """Validate & post-process options before freezing."""
+
+  @classmethod
   def AddDeviceArgument(cls, parser, schemes=commandline.DEVICE_SCHEME_SSH,
                         positional=False):
     """Add a device argument to the parser.
diff --git a/cli/command_unittest.py b/cli/command_unittest.py
index 98890ca..8848307 100644
--- a/cli/command_unittest.py
+++ b/cli/command_unittest.py
@@ -19,7 +19,7 @@
 _COMMAND_NAME = 'superAwesomeCommandOfFunness'
 
 
-@command.CommandDecorator(_COMMAND_NAME)
+@command.command_decorator(_COMMAND_NAME)
 class TestCommand(command.CliCommand):
   """A fake command."""
   def Run(self):
@@ -45,14 +45,14 @@
     """Tests that our decorator correctly rejects bad test commands."""
     try:
       # pylint: disable=unused-variable
-      @command.CommandDecorator('bad')
+      @command.command_decorator('bad')
       class BadTestCommand(object):
         """A command that wasn't implemented correctly."""
 
     except command.InvalidCommandError:
       pass
     else:
-      self.fail('Invalid command was accepted by the CommandDecorator')
+      self.fail('Invalid command was accepted by @command_decorator')
 
   def testAddDeviceArgument(self):
     """Tests CliCommand.AddDeviceArgument()."""
@@ -81,7 +81,7 @@
     self.args = args
     self.rc_mock = cros_test_lib.RunCommandMock()
     self.rc_mock.SetDefaultCmdResult()
-    parser = commandline.ArgumentParser(caching=True)
+    self.parser = parser = commandline.ArgumentParser(caching=True)
     subparsers = parser.add_subparsers()
     subparser = subparsers.add_parser(self.COMMAND, caching=True)
     self.TARGET_CLASS.AddParser(subparser)
diff --git a/cli/command_vm_test.py b/cli/command_vm_test.py
index 8e9ee3c..3a3fa47 100644
--- a/cli/command_vm_test.py
+++ b/cli/command_vm_test.py
@@ -42,7 +42,7 @@
                  command, content.rstrip(), command)
 
 
-def TestCommandDecorator(command_name):
+def test_command_decorator(command_name):
   """Decorator that runs the command test function."""
 
   def Decorator(test_function):
@@ -69,7 +69,7 @@
 
   This class provides the abstract interface for testing CLI commands on a VM.
   The sub-class must define the BuildCommand method in order to be usable. And
-  the test functions must use the TestCommandDecorator decorator.
+  the test functions must use the test_command_decorator decorator.
   """
 
   def __init__(self, board, image_path):
@@ -114,7 +114,7 @@
                        cwd=constants.CHROMITE_BIN_DIR,
                        check=False)
 
-  @TestCommandDecorator('shell')
+  @test_command_decorator('shell')
   def TestShell(self):
     """Tests the shell command."""
     # The path and content of a temporary file for testing shell command.
@@ -148,7 +148,7 @@
       logging.error('Failed to remove the file on the VM device.')
       raise CommandError(result.error)
 
-  @TestCommandDecorator('debug')
+  @test_command_decorator('debug')
   def TestDebug(self):
     """Tests the debug command."""
     logging.info('Test to start and debug a new process on the VM device.')
@@ -178,7 +178,7 @@
         logging.error('Failed to attach a running process on the VM device.')
         raise CommandError(result.error)
 
-  @TestCommandDecorator('flash')
+  @test_command_decorator('flash')
   def TestFlash(self):
     """Tests the flash command."""
     # We explicitly disable reboot after the update because VMs sometimes do
@@ -194,7 +194,7 @@
       logging.error('Failed to flash the VM device.')
       raise CommandError(result.error)
 
-  @TestCommandDecorator('deploy')
+  @test_command_decorator('deploy')
   def TestDeploy(self):
     """Tests the deploy command."""
     packages = ['dev-python/cherrypy', 'app-portage/portage-utils']
diff --git a/cli/cros/README.cros_moblabvm.md b/cli/cros/README.cros_moblabvm.md
index 3b2c29d..8bae240 100644
--- a/cli/cros/README.cros_moblabvm.md
+++ b/cli/cros/README.cros_moblabvm.md
@@ -265,10 +265,9 @@
 For this, instead of downloading a moblab image from a builder, build the image
 yourself.
 ```
-pprabhu@pprabhu:chromiumos$ cros_sdk
-(cr) ((8e3381b52...)) pprabhu@pprabhu ~/trunk/src/scripts $ ./build_packages --board moblab-generic-vm
+~/chromiumos/src/scripts $ ./build_packages --board moblab-generic-vm
 ...
-(cr) ((8e3381b52...)) pprabhu@pprabhu ~/trunk/src/scripts $ ./build_image --board moblab-generic-vm --noenable_rootfs_verification test
+~/chromiumos/src/scripts $ ./build_image --board moblab-generic-vm --noenable_rootfs_verification test
 ...
 ```
 
@@ -280,13 +279,13 @@
 Continuing the example above, if you were working on autotest infrastructure
 code:
 ```
-(cr) ((8e3381b52...)) pprabhu@pprabhu ~/trunk/src/scripts $ cros_workon --board moblab-generic-vm start chromeos-base/autotest-server
+(inside) $ cros_workon --board moblab-generic-vm start chromeos-base/autotest-server
 11:13:26: INFO: Started working on 'chromeos-base/autotest-server' for 'moblab-generic-vm'
 ```
 Make changes to autotest as needed, then deploy the changes to moblab.
 ```
-(cr) ((8e3381b52...)) pprabhu@pprabhu ~/trunk/src/scripts $ emerge-moblab-generic-vm chromeos-base/autotest-server
-pprabhu@pprabhu:~$ cros deploy localhost:16482 chromeos-base/autotest-server
+(inside) $ emerge-moblab-generic-vm chromeos-base/autotest-server
+$ cros deploy localhost:16482 chromeos-base/autotest-server
 ```
 Finally, restart any services on moblab that may have been affected. You can
 find relevant services by running `ls /etc/init | grep moblab`.
@@ -298,10 +297,12 @@
 
 If you're working on devserver instead, you want:
 ```
-(cr) ((8e3381b52...)) pprabhu@pprabhu ~/trunk/src/scripts $ cros_workon --board moblab-generic-vm start chromeos-base/devserver
-(cr) ((8e3381b52...)) pprabhu@pprabhu ~/trunk/src/scripts $ emerge-moblab-generic-vm chromeos-base/devserver
-pprabhu@pprabhu:~$ cros deploy localhost:16482 chromeos-base/devserver
+(inside)
+$ cros_workon --board moblab-generic-vm start chromeos-base/devserver
+$ emerge-moblab-generic-vm chromeos-base/devserver
+$ cros deploy localhost:16482 chromeos-base/devserver
 ```
+
 # Troubleshooting
 
 For most errors, the first thing to do is to rerun with `--debug`. This may make
diff --git a/cli/cros/cros_analyze_image.py b/cli/cros/cros_analyze_image.py
index 56f8e69..bd0681a 100644
--- a/cli/cros/cros_analyze_image.py
+++ b/cli/cros/cros_analyze_image.py
@@ -190,18 +190,18 @@
       pformat.json(output, f)
 
 
-@command.CommandDecorator('analyze-image')
+@command.command_decorator('analyze-image')
 class AnalyzeImageCommand(command.CliCommand):
   """Analyze cros images listing large directory and file sizes."""
 
-  def __init__(self, options: commandline.ArgumentNamespace):
-    super().__init__(options)
-
-    if self.options.image:
+  @classmethod
+  def ProcessOptions(cls, parser, options):
+    """Post process options."""
+    if options.image:
       return
 
-    if not self.options.board or not self.options.version:
-      cros_build_lib.Die('--image or (--board and --version) required')
+    if not options.board or not options.version:
+      parser.error('--image or (--board and --version) required')
 
   def Run(self):
     """Perform the command."""
diff --git a/cli/cros/cros_ap.py b/cli/cros/cros_ap.py
index 85d5c81..5c609ea 100644
--- a/cli/cros/cros_ap.py
+++ b/cli/cros/cros_ap.py
@@ -8,28 +8,38 @@
 import logging
 import os
 from pathlib import Path
-import sys
 
 from chromite.cli import command
 from chromite.lib import build_target_lib
 from chromite.lib import commandline
-from chromite.lib import constants
 from chromite.lib import cros_build_lib
-from chromite.lib.firmware import ap_firmware
-from chromite.lib.firmware import flash_ap
-from chromite.lib.firmware import servo_lib
-from chromite.utils import file_util
-from chromite.utils import pformat
+from chromite.lib.firmware import dut
+from chromite.lib.firmware import firmware_config
+from chromite.lib.firmware import firmware_lib
 
 
-COMMAND_DUMP_CONFIG = 'dump-config'
-COMMAND_BUILD = 'build'
-COMMAND_FLASH = 'flash'
-COMMAND_READ = 'read'
-COMMAND_CLEAN = 'clean'
+# All known ap subcommands.
+SUBCOMMANDS = {}
 
 
-@command.CommandDecorator('ap')
+def subcommand_decorator(name):
+  """Decorator that validates and registers subcommands."""
+
+  def inner_decorator(original_class):
+    """Inner decorator that actually wraps the class."""
+    assert hasattr(original_class, '__doc__'), f'{name}: missing docstring'
+
+    assert issubclass(original_class, command.CliCommand), (
+        f'{original_class}: subcommands must derive from CliCommand')
+
+    SUBCOMMANDS[name] = original_class
+
+    return original_class
+
+  return inner_decorator
+
+
+@command.command_decorator('ap')
 class APCommand(command.CliCommand):
   """Execute an AP-related command."""
 
@@ -43,75 +53,37 @@
         title='AP subcommands', dest='ap_command')
     subparsers.required = True
 
-    dump_config_parser = _AddSubparser(parser, subparsers, COMMAND_DUMP_CONFIG,
-                                       'Dump the AP Config to a file.')
-    DumpConfigSubcommand.AddParser(dump_config_parser)
+    for name, subcommand_class in SUBCOMMANDS.items():
+      sub_parser = subparsers.add_parser(
+          name,
+          description=subcommand_class.__doc__,
+          caching=parser.caching,
+          help=subcommand_class.__doc__,
+          formatter_class=parser.formatter_class)
+      subcommand_class.AddParser(sub_parser)
 
-    build_parser = _AddSubparser(
-        parser, subparsers, COMMAND_BUILD,
-        'Build the AP Firmware for the requested build target.')
-    BuildSubcommand.AddParser(build_parser)
-
-    flash_parser = _AddSubparser(parser, subparsers, COMMAND_FLASH,
-                                 'Update the AP Firmware on a device.')
-    FlashSubcommand.AddParser(flash_parser)
-
-    read_parser = _AddSubparser(parser, subparsers, COMMAND_READ,
-                                'Read the AP Firmware from a device.')
-    ReadSubcommand.AddParser(read_parser)
-
-    clean_parser = _AddSubparser(parser, subparsers, COMMAND_CLEAN,
-                                 'Clean up dependencies and artifacts '
-                                 'for a given build target.')
-    CleanSubcommand.AddParser(clean_parser)
+  @classmethod
+  def ProcessOptions(cls, parser, options):
+    """Post process options."""
+    sub_class = SUBCOMMANDS[options.ap_command]
+    sub_class.ProcessOptions(parser, options)
 
   def Run(self):
     """The main handler of this CLI."""
-    if self.options.ap_command == COMMAND_DUMP_CONFIG:
-      subcmd = DumpConfigSubcommand(self.options)
-    elif self.options.ap_command == COMMAND_BUILD:
-      subcmd = BuildSubcommand(self.options)
-    elif self.options.ap_command == COMMAND_FLASH:
-      subcmd = FlashSubcommand(self.options)
-    elif self.options.ap_command == COMMAND_READ:
-      subcmd = ReadSubcommand(self.options)
-    elif self.options.ap_command == COMMAND_CLEAN:
-      subcmd = CleanSubcommand(self.options)
-    subcmd.Run()
+    cls = SUBCOMMANDS[self.options.ap_command]
+    subcmd = cls(self.options)
+    return subcmd.Run()
 
 
-def _AddSubparser(parser, subparsers, name, description):
-  """Adds a subparser to the given parser, with common options.
-
-  Forwards some options from the parser to the new subparser to ensure
-  consistent formatting of output etc.
-
-  Args:
-    parser: The parent parser for this subparser.
-    subparsers: The subparsers group to add this subparser to.
-    name: Name of the new sub-command.
-    description: Description to be used for the sub-command.
-
-  Returns:
-    The new subparser.
-  """
-  return subparsers.add_parser(
-      name,
-      description=description,
-      caching=parser.caching,
-      help=description,
-      formatter_class=parser.formatter_class,
-  )
-
-
+@subcommand_decorator('dump-config')
 class DumpConfigSubcommand(command.CliCommand):
   """Dump the AP Config to a file."""
 
-  def __init__(self, options):
-    super().__init__(options)
-    if self.options.output:
-      self.options.output = Path(self.options.output)
-    self.options.Freeze()
+  @classmethod
+  def ProcessOptions(cls, parser, options):
+    """Post process options."""
+    if options.output:
+      options.output = Path(options.output)
 
   @classmethod
   def AddParser(cls, parser):
@@ -141,71 +113,21 @@
 
   def Run(self):
     """Perform the cros ap dump-config command."""
-    boards = []
+    boards = None
     if self.options.boards:
       boards = self.options.boards
-    else:
-      # Get the board list from config python modules in
-      # chromite/lib/firmware/ap_firmware_config
-      path_to_firmware_configs = (
-          Path(constants.CHROMITE_DIR) / 'lib' / 'firmware' /
-          'ap_firmware_config')
-      for p in path_to_firmware_configs.glob('*.py'):
-        if not p.is_file():
-          continue
-        if p.name.startswith('_'):
-          continue
-        # Remove paths, leaving only filenames, and remove .py suffixes.
-        boards.append(p.with_suffix('').name)
-    boards.sort()
 
-    if self.options.output:
-      output_path = self.options.output
-      logging.info('Dumping AP config to %s', output_path)
-      logging.info('List of boards: %s', ', '.join(boards))
-      logging.info('List of servos: %s', ', '.join(servo_lib.VALID_SERVOS))
-    else:
-      output_path = sys.stdout
-
-    output = {}
-    failed_board_servos = {}
-    for board in boards:
-      module = ap_firmware.get_config_module(board)
-      output[board] = {}
-      for servo_version in servo_lib.VALID_SERVOS:
-        servo = servo_lib.Servo(servo_version, self.options.serial)
-        # get_config() call is expected to fail for some board:servo pairs.
-        # Disable logging to avoid inconsistent error messages from config
-        # modules' get_config() calls.
-        logging.disable(logging.CRITICAL)
-        try:
-          ap_config = module.get_config(servo)
-        except servo_lib.UnsupportedServoVersionError:
-          failed_board_servos.setdefault(board, []).append(servo_version)
-          continue
-        finally:
-          # Reenable logging.
-          logging.disable(logging.DEBUG)
-
-        output[board][servo_version] = {
-            'dut_control_on': ap_config.dut_control_on,
-            'dut_control_off': ap_config.dut_control_off,
-            'programmer': ap_config.programmer,
-        }
-    for board, servos in failed_board_servos.items():
-      logging.notice(f'[{board}] skipping servos ' f'{", ".join(servos)}')
-
-    with file_util.Open(output_path, 'w', encoding='utf-8') as f:
-      pformat.json(output, f)
+    firmware_config.export_config_as_json(boards, self.options.output,
+                                          self.options.serial)
 
 
+@subcommand_decorator('build')
 class BuildSubcommand(command.CliCommand):
   """Build the AP Firmware for the requested build target."""
 
   def __init__(self, options):
     super().__init__(options)
     self.build_target = build_target_lib.BuildTarget(self.options.build_target)
-    self.options.Freeze()
 
   @classmethod
   def AddParser(cls, parser):
@@ -242,23 +164,24 @@
     commandline.RunInsideChroot(self)
 
     try:
-      ap_firmware.build(
+      firmware_lib.build(
           self.build_target,
           fw_name=self.options.fw_name,
           dry_run=self.options.dry_run)
-    except ap_firmware.Error as e:
+    except firmware_lib.Error as e:
       cros_build_lib.Die(e)
 
 
+@subcommand_decorator('read')
 class ReadSubcommand(command.CliCommand):
   """Read the AP Firmware from a device."""
 
-  def __init__(self, options):
-    super().__init__(options)
-    if self.options.device is None:
-      cros_build_lib.Die('Specify device using --device argument.')
-    self.options.output_path = Path(self.options.output)
-    self.options.Freeze()
+  @classmethod
+  def ProcessOptions(cls, parser, options):
+    """Post process options."""
+    if options.device is None:
+      parser.error('Specify device using --device argument.')
+    options.output_path = Path(options.output)
 
   @classmethod
   def AddParser(cls, parser):
@@ -275,10 +198,10 @@
         dest='build_target',
         help='The name of the build target.')
     parser.add_argument('-r'
-                           '--region',
-                           dest='region',
-                           type=str,
-                           help='Region to read.')
+                        '--region',
+                        dest='region',
+                        type=str,
+                        help='Region to read.')
     parser.add_argument(
         '-o', '--output', type='path', required=True, help='Output file.')
     parser.add_argument(
@@ -323,14 +246,13 @@
       region = self.options.region
 
     if ip:
-      flash_ap.ssh_read(self.options.output, self.options.verbose, ip, port,
-                        self.options.dry_run, region)
+      firmware_lib.ssh_read(self.options.output, self.options.verbose, ip, port,
+                            self.options.dry_run, region)
     else:
-      dut_ctl = servo_lib.DutControl(port)
-      servo = servo_lib.get(dut_ctl)
+      dut_ctl = dut.DutControl(port)
+      servo = dut_ctl.get_servo()
 
-      config_module = ap_firmware.get_config_module(build_target.name)
-      ap_config = config_module.get_config(servo)
+      ap_config = firmware_config.get_config(build_target.name, servo)
 
       flashrom_cmd = [
           'flashrom', '-p', ap_config.programmer, '-r', self.options.output
@@ -339,28 +261,29 @@
         flashrom_cmd += ['-V']
       if region:
         flashrom_cmd += ['-i', self.options.region]
-      if not flash_ap.servo_run(dut_ctl, ap_config.dut_control_on,
-                                ap_config.dut_control_off, flashrom_cmd,
-                                self.options.verbose, self.options.dry_run):
+      if not dut_ctl.servo_run(ap_config.dut_control_on,
+                               ap_config.dut_control_off, flashrom_cmd,
+                               self.options.verbose, self.options.dry_run):
         logging.error('Unable to read, verify servo connection '
                       'is correct and servod is running in the background.')
 
 
+@subcommand_decorator('flash')
 class FlashSubcommand(command.CliCommand):
   """Update the AP Firmware on a device."""
 
-  def __init__(self, options):
-    super().__init__(options)
-    if not os.path.exists(self.options.image):
-      cros_build_lib.Die(
-          '%s does not exist, verify the path of your build and try '
-          'again.', self.options.image)
+  @classmethod
+  def ProcessOptions(cls, parser, options):
+    """Post process options."""
+    if not os.path.exists(options.image):
+      parser.error(
+          f'{options.image} does not exist, verify the path of your build and '
+          'try again.')
     if options.fast:
-      cros_build_lib.Die(
+      parser.error(
           'Flags such as --fast must be passed directly after --\n'
           'For futility use: cros ap flash ${OTHER_ARGS} -- --fast\n'
           'For flashrom use: cros ap flash --flashrom ${OTHER_ARGS} -- -n')
-    self.options.Freeze()
 
   @classmethod
   def AddParser(cls, parser):
@@ -431,27 +354,26 @@
 
     build_target = build_target_lib.BuildTarget(self.options.build_target)
     try:
-      ap_firmware.deploy(
+      firmware_lib.deploy(
           build_target,
           self.options.image,
           self.options.device,
           flashrom=self.options.flashrom,
-          fast=False,
           verbose=self.options.verbose,
           dryrun=self.options.dry_run,
           flash_contents=self.options.flash_contents,
           passthrough_args=passthrough_args)
-    except ap_firmware.Error as e:
+    except firmware_lib.Error as e:
       cros_build_lib.Die(e)
 
 
+@subcommand_decorator('clean')
 class CleanSubcommand(command.CliCommand):
-  """Clean packages and artifacts for the requested build target."""
+  """Clean up dependencies and artifacts for the requested build target."""
 
   def __init__(self, options):
     super().__init__(options)
     self.build_target = build_target_lib.BuildTarget(self.options.build_target)
-    self.options.Freeze()
 
   @classmethod
   def AddParser(cls, parser):
@@ -480,6 +402,6 @@
     commandline.RunInsideChroot(self)
 
     try:
-      ap_firmware.clean(self.build_target, self.options.dry_run)
-    except ap_firmware.Error as e:
+      firmware_lib.clean(self.build_target, self.options.dry_run)
+    except firmware_lib.Error as e:
       cros_build_lib.Die(e)
diff --git a/cli/cros/cros_ap_dumpconfig_unittest.py b/cli/cros/cros_ap_dumpconfig_unittest.py
index 1c1c23e..1ebd590 100644
--- a/cli/cros/cros_ap_dumpconfig_unittest.py
+++ b/cli/cros/cros_ap_dumpconfig_unittest.py
@@ -11,7 +11,6 @@
 from chromite.lib import cros_test_lib
 from chromite.lib.firmware import servo_lib
 
-
 pytestmark = cros_test_lib.pytestmark_inside_only
 
 
@@ -24,6 +23,7 @@
 
   def testCrosConfigDump(self):
     """Run cros dump-ap-config, read the output, and check validity."""
+    allowed_servos = servo_lib.VALID_SERVOS + ('ssh',)
     output_file = Path(self.tempdir) / 'tmp.json'
     cmd = ['cros', 'ap', 'dump-config', '-o', str(output_file)]
     cros_build_lib.run(cmd)
@@ -40,7 +40,7 @@
     for board, board_config in result.items():
       assert board
       for servo, configs in board_config.items():
-        assert servo in servo_lib.VALID_SERVOS
+        assert servo in allowed_servos
         assert 'dut_control_on' in configs
         if configs['dut_control_on']:
           seen_dut_control_on = True
diff --git a/cli/cros/cros_build.py b/cli/cros/cros_build.py
index 72fde04..5d10f1f 100644
--- a/cli/cros/cros_build.py
+++ b/cli/cros/cros_build.py
@@ -26,7 +26,7 @@
   """
 
 
-@command.CommandDecorator('build')
+@command.command_decorator('build')
 class BuildCommand(command.CliCommand):
   """Build the requested packages."""
 
@@ -146,8 +146,6 @@
 
   def Run(self):
     """Run cros build."""
-    self.options.Freeze()
-
     if not self.host:
       if not self.board:
         cros_build_lib.Die('You did not specify a board to build for. '
diff --git a/cli/cros/cros_buildresult.py b/cli/cros/cros_buildresult.py
index 1d53c90..ae5c29f 100644
--- a/cli/cros/cros_buildresult.py
+++ b/cli/cros/cros_buildresult.py
@@ -132,7 +132,7 @@
   return json.dumps(report)
 
 
-@command.CommandDecorator('buildresult')
+@command.command_decorator('buildresult')
 class BuildResultCommand(command.CliCommand):
   """Script that looks up results of finished builds."""
 
@@ -150,7 +150,7 @@
   cros buildresult --buildbucket-id 1234567890123 --report json
 
 Note:
-  This tool does NOT work for master-*-tryjob, precq-launcher-try, or
+  This tool does NOT work for main-*-tryjob, precq-launcher-try, or
   builds on branches older than CL:942097.
 
 Note:
@@ -193,8 +193,6 @@
 
   def Run(self):
     """Run cros buildresult."""
-    self.options.Freeze()
-
     commandline.RunInsideChroot(self)
 
     buildstore = BuildStore(_write_to_cidb=False)
diff --git a/cli/cros/cros_chrome_sdk.py b/cli/cros/cros_chrome_sdk.py
index 51b8b21..de3d094 100644
--- a/cli/cros/cros_chrome_sdk.py
+++ b/cli/cros/cros_chrome_sdk.py
@@ -20,6 +20,7 @@
 
 from chromite.third_party.gn_helpers import gn_helpers
 
+from chromite.cbuildbot import commands
 from chromite.cli import command
 from chromite.lib import cache
 from chromite.lib import chromite_config
@@ -109,7 +110,7 @@
   def __init__(self, cache_dir, board, clear_cache=False, chrome_src=None,
                sdk_path=None, toolchain_path=None, silent=False,
                use_external_config=None,
-               fallback_versions=VERSIONS_TO_CONSIDER):
+               fallback_versions=VERSIONS_TO_CONSIDER, is_lacros=False):
     """Initialize the class.
 
     Args:
@@ -127,6 +128,7 @@
         force usage of the external configuration if both external and internal
         are available.
       fallback_versions: The number of versions to consider.
+      is_lacros: whether it's Lacros-Chrome build or not.
     """
     site_config = config_lib.GetConfig()
 
@@ -150,6 +152,7 @@
     self.toolchain_path = toolchain_path
     self.fallback_versions = fallback_versions
     self.silent = silent
+    self.is_lacros = is_lacros
 
     # For external configs, there is no need to run 'gsutil config', because
     # the necessary files are all accessible to anonymous users.
@@ -235,7 +238,7 @@
 
   @staticmethod
   def GetChromeLKGM(chrome_src_dir=None):
-    """Get ChromeOS LKGM checked into the Chrome tree.
+    """Get the CHROMEOS LKGM checked into the Chrome tree.
 
     Args:
       chrome_src_dir: chrome source directory.
@@ -789,7 +792,7 @@
   """Indicates error with setting up Goma."""
 
 
-@command.CommandDecorator(COMMAND_NAME)
+@command.command_decorator(COMMAND_NAME)
 class ChromeSDKCommand(command.CliCommand):
   """Set up an environment for building Chrome on Chrome OS.
 
@@ -966,6 +969,12 @@
     parser.add_argument(
         '--cfi', action='store_true', default=False,
         help='Enable CFI in build.')
+    parser.add_argument(
+        '--is-lacros', action='store_true', default=False,
+        help='Whether it is Lacros-Chrome build or not. This is temporarily '
+             'added to work around a Lacros CrOS toolchain bug due to version '
+             'skew, and should be removed once Lacros is swiched to use '
+             'Chromium toolchain: crbug.com/1275386.')
 
     parser.caching_group.add_argument(
         '--clear-sdk-cache', action='store_true',
@@ -984,6 +993,29 @@
         help='Override toolchain url format pattern, e.g. '
              '2014/04/%%(target)s-2014.04.23.220740.tar.xz')
 
+  @classmethod
+  def ProcessOptions(cls, parser, options):
+    """Post process options."""
+    if bool(options.board) == bool(options.boards):
+      parser.error('Must specify either one of --board or --boards.')
+
+    if options.boards and options.use_shell:
+      parser.error('Must specify --no-shell when preparing multiple boards.')
+
+    if options.is_lacros and not options.version:
+      parser.error(
+          'Must specify --version for --is-lacros because Lacros-Chrome build '
+          'does not use the CHROMEOS_LKGM version for compilation')
+
+    src_path = options.chrome_src or os.getcwd()
+    checkout = path_util.DetermineCheckout(src_path)
+    if not checkout.chrome_src_dir:
+      parser.error(f'Chrome checkout not found at {src_path}')
+    options.chrome_src = checkout.chrome_src_dir
+
+    if options.boards:
+      options.boards = options.boards.split(':')
+
   def __init__(self, options):
     super().__init__(options)
     self.board = options.board
@@ -1024,9 +1056,10 @@
   def _SaveSharedGnArgs(self, gn_args, board):
     """Saves the new gn args data to the shared location."""
     shared_dir = os.path.join(self.options.chrome_src, self._BUILD_ARGS_DIR)
-
-    file_path = os.path.join(shared_dir, board + '.gni')
-    osutils.WriteFile(file_path, gn_helpers.ToGNString(gn_args))
+    if not self.options.is_lacros:
+      file_path = os.path.join(shared_dir, board + '.gni')
+      osutils.WriteFile(file_path, gn_helpers.ToGNString(gn_args))
+      return
 
     # If the board is a generic family, generate -crostoolchain.gni files,
     # too, which is used by Lacros build.
@@ -1149,74 +1182,30 @@
       return os.path.join(tc_path, 'bin', binary)
     return binary
 
-  def _GenerateReclientConfig(self, sdk_ctx, board):
-    """Generate a config and a wrapper for reclient.
+  def _GenerateReclientWrapper(self, board):
+    """Generate a wrapper for reclient.
 
-    This function generates a configuration to be used by rewrapper
-    (rewrapper_<board>.cfg) and a wrapper script for the rewrapper to make it
+    This function generates a wrapper script for the rewrapper to make it
     passed with --gomacc-path (rewrapper_<board>).
-    The configuration is based on the linux configuration, which has already
-    been installed in Chromium repository, and this function adds a flag to
-    preserve symlink and updates inputs so that the configuration can be used
-    for compiling with ChromeOS clang.
+    The wrapper adds a flag to preserve symlinks which are used by CrOS clang.
 
     Args:
-      sdk_ctx: An SDKFetcher.SDKContext namedtuple object for getting toolchain
-               location.
       board: Target board name to be used as a config name and a wrapper name.
 
     Returns:
       Absolute path to the wrapper script to be used as --gomacc-path.
     """
     shared_dir = os.path.join(self.options.chrome_src, self._BUILD_ARGS_DIR)
-    tc_tarball_path = os.path.realpath(
-        sdk_ctx.key_map[self.sdk.TARGET_TOOLCHAIN_KEY].path)
-    linux_cfg_path = os.path.join(self.options.chrome_src, 'buildtools',
-                                  'reclient_cfgs', 'rewrapper_linux.cfg')
-    linux_cfg = osutils.ReadFile(linux_cfg_path).splitlines()
-
-    # TODO(b:190794287): remove code for inputs.  It will eventually be
-    #                    provided by the file in the toolchain tarball.
-    inputs = [
-        'usr/bin/clang',
-        'usr/bin/clang++',
-        'usr/bin/clang++-13',
-        'usr/bin/clang-13',
-        'usr/bin/clang-13.elf',
-        'usr/bin/clang++-13.elf',
-        'lib/ld-linux-x86-64.so.2',
-        'lib/libc++abi.so.1',
-        'lib/libc++.so.1',
-        'lib/libc.so.6',
-        'lib/libdl.so.2',
-        'lib/libgcc_s.so.1',
-        'lib/libm.so.6',
-        'lib/libpthread.so.0',
-        'lib/libtinfo.so.5',
-        'lib/libz.so.1',
-    ]
-    rel_tc_tarball_path = os.path.relpath(tc_tarball_path,
-                                          self.options.chrome_src)
-    inputs = [os.path.join(rel_tc_tarball_path, i) for i in inputs]
-    cros_cfg = ['preserve_symlink=true']
-    for line in linux_cfg:
-      if line.startswith('inputs='):
-        line = 'inputs=%s' % ','.join(inputs)
-      cros_cfg.append(line)
-    cros_cfg_path = os.path.join(shared_dir, f'rewrapper_{board}.cfg')
-    osutils.WriteFile(cros_cfg_path, '\n'.join(cros_cfg))
-    Log('generated rewrapper_cfg %s', cros_cfg_path, silent=self.silent)
 
     # TODO(b:190741226): remove the wrapper if the compiler wrapper supports
     #                    flags for reclient.
     wrapper_path = os.path.join(shared_dir, 'rewrapper_%s' % board)
     wrapper_content = [
         '#!/bin/sh\n',
-        '%(rewrapper_dir)s/rewrapper -cfg="%(cros_cfg_path)s" '
+        '%(rewrapper_dir)s/rewrapper -preserve_symlink=true '
         '-exec_root="%(chrome_src)s" "$@"\n' % {
             'rewrapper_dir': os.path.join(
                 self.options.chrome_src, 'buildtools', 'reclient'),
-            'cros_cfg_path': cros_cfg_path,
             'chrome_src': self.options.chrome_src},
     ]
     osutils.WriteFile(wrapper_path, wrapper_content, chmod=0o755)
@@ -1278,7 +1267,15 @@
     # Add board and sdk version as gn args so that tests can bind them in
     # test wrappers generated at compile time.
     gn_args['cros_board'] = board
-    gn_args['cros_sdk_version'] = sdk_ctx.version
+
+    if options.is_lacros:
+      # The 'cros_sdk_version' is used by the chromium BUILD files to decide
+      # the runtime dependencies to isolate for swarming based testing, and
+      # given that Lacros uses CHROMEOS_LKGM for testing regardless of the
+      # version used for compilation, so always set the value as CHROME_LKGM.
+      gn_args['cros_sdk_version'] = SDKFetcher.GetChromeLKGM(options.chrome_src)
+    else:
+      gn_args['cros_sdk_version'] = sdk_ctx.version
 
     # Export the board/version info in a more accessible way, so developers can
     # reference them in their chrome_sdk.bashrc files, as well as within the
@@ -1395,8 +1392,7 @@
                    '--gn-extra-args to specify a non default value.',
                    symbol_level)
 
-    gn_args['rbe_cros_cc_wrapper'] = self._GenerateReclientConfig(
-        sdk_ctx, board)
+    gn_args['rbe_cros_cc_wrapper'] = self._GenerateReclientWrapper(board)
 
     if options.gn_extra_args:
       gn_args.update(gn_helpers.FromGNArgs(options.gn_extra_args))
@@ -1546,13 +1542,6 @@
 
   def Run(self):
     """Perform the command."""
-    if bool(self.options.board) == bool(self.options.boards):
-      cros_build_lib.Die('Must specify either one of --board or --boards.')
-
-    if self.options.boards and self.options.use_shell:
-      cros_build_lib.Die(
-          'Must specify --no-shell when preparing multiple boards.')
-
     if os.environ.get(SDKFetcher.SDK_VERSION_ENV) is not None:
       cros_build_lib.Die('Already in an SDK shell.')
 
@@ -1566,12 +1555,6 @@
       except OSError:
         pass
 
-    src_path = self.options.chrome_src or os.getcwd()
-    checkout = path_util.DetermineCheckout(src_path)
-    if not checkout.chrome_src_dir:
-      cros_build_lib.Die('Chrome checkout not found at %s', src_path)
-    self.options.chrome_src = checkout.chrome_src_dir
-
     if self.options.chrome_branding or self.options.internal:
       gclient_path = gclient.FindGclientFile(self.options.chrome_src)
       if not gclient_path:
@@ -1603,7 +1586,6 @@
     if self.options.board:
       return self._RunOnceForBoard(self.options.board)
     else:
-      self.options.boards = self.options.boards.split(':')
       for board in self.options.boards:
         start = datetime.datetime.now()
         self._RunOnceForBoard(board)
@@ -1627,7 +1609,8 @@
         toolchain_path=self.options.toolchain_path,
         silent=self.silent,
         use_external_config=self.options.use_external_config,
-        fallback_versions=self.options.fallback_versions
+        fallback_versions=self.options.fallback_versions,
+        is_lacros=self.options.is_lacros
     )
 
     prepare_version = self.options.version
@@ -1637,6 +1620,7 @@
     components = [self.sdk.TARGET_TOOLCHAIN_KEY, constants.CHROME_ENV_TAR]
     if not self.options.chroot:
       components.append(constants.CHROME_SYSROOT_TAR)
+      components.append(commands.AUTOTEST_SERVER_PACKAGE)
     if self.options.download_vm:
       components.append(constants.TEST_IMAGE_TAR)
 
diff --git a/cli/cros/cros_chrome_sdk_unittest.py b/cli/cros/cros_chrome_sdk_unittest.py
index c98f441..9885e9a 100644
--- a/cli/cros/cros_chrome_sdk_unittest.py
+++ b/cli/cros/cros_chrome_sdk_unittest.py
@@ -230,10 +230,6 @@
       cmd_args += ['--board', SDKFetcherMock.BOARD]
     if extra_args:
       cmd_args.extend(extra_args)
-    # rewrapper_linux.cfg is used as a reference. The file must exist.
-    osutils.Touch(os.path.join(self.chrome_root, 'src', 'buildtools',
-                               'reclient_cfgs', 'rewrapper_linux.cfg'),
-                  makedirs=True)
     # --no-shell drops gni files in //build/args/chromeos/.
     # reclient configs are also dropped here regardless of --no-shell or not.
     osutils.SafeMakedirs(
@@ -291,6 +287,8 @@
   def testManyBoards(self):
     """Test a runthrough when multiple boards are specified via --boards."""
     self.SetupCommandMock(many_boards=True)
+    self.cmd_mock.inst.ProcessOptions(
+        self.cmd_mock.parser, self.cmd_mock.inst.options)
     self.cmd_mock.inst.Run()
     for board in SDKFetcherMock.BOARDS:
       board_arg_file = os.path.join(
@@ -301,7 +299,31 @@
       board_crostoolchain_arg_file = os.path.join(
           self.chrome_src_dir,
           'build/args/chromeos/%s-crostoolchain.gni' % board)
+      self.assertNotExists(board_crostoolchain_arg_file)
+
+  def testManyBoardsLacros(self):
+    """Test a runthrough when multiple boards are specified via --boards."""
+    self.SetupCommandMock(many_boards=True,
+                          extra_args=['--is-lacros', '--version=1234.0.0'])
+    lkgm_file = os.path.join(self.chrome_src_dir, constants.PATH_TO_CHROME_LKGM)
+    osutils.Touch(lkgm_file, makedirs=True)
+    osutils.WriteFile(lkgm_file, '5678.0.0')
+
+    self.cmd_mock.inst.ProcessOptions(
+        self.cmd_mock.parser, self.cmd_mock.inst.options)
+    self.cmd_mock.inst.Run()
+    for board in SDKFetcherMock.BOARDS:
+      board_arg_file = os.path.join(
+          self.chrome_src_dir, 'build/args/chromeos/%s.gni' % board)
+      self.assertNotExists(board_arg_file)
+      # Because board is either amd64-generic or arm-generic,
+      # it is a target to create -crostoolchain.gni files, too.
+      board_crostoolchain_arg_file = os.path.join(
+          self.chrome_src_dir,
+          'build/args/chromeos/%s-crostoolchain.gni' % board)
       self.assertExists(board_crostoolchain_arg_file)
+      with open(board_crostoolchain_arg_file) as f:
+        self.assertIn('cros_sdk_version = "5678.0.0"', f.read())
 
   def testManyBoardsBrokenArgs(self):
     """Tests that malformed args.gn files will be fixed in --boards."""
@@ -311,6 +333,8 @@
           self.chrome_src_dir, 'out_%s' % board, 'Release', 'args.gn')
       osutils.WriteFile(gn_args_file, 'foo\nbar', makedirs=True)
 
+    self.cmd_mock.inst.ProcessOptions(
+        self.cmd_mock.parser, self.cmd_mock.inst.options)
     self.cmd_mock.inst.Run()
 
     for board in SDKFetcherMock.BOARDS:
@@ -714,6 +738,7 @@
     lkgm_file = os.path.join(gclient_root, 'src', constants.PATH_TO_CHROME_LKGM)
     osutils.Touch(lkgm_file, makedirs=True)
     osutils.WriteFile(lkgm_file, self.VERSION)
+
     self.sdk_mock.UnMockAttr('UpdateDefaultVersion')
     self.sdk.UpdateDefaultVersion()
     self.assertEqual(self.sdk.GetDefaultVersion(),
diff --git a/cli/cros/cros_chroot.py b/cli/cros/cros_chroot.py
index 9102a1e..ade79d1 100644
--- a/cli/cros/cros_chroot.py
+++ b/cli/cros/cros_chroot.py
@@ -11,7 +11,7 @@
 from chromite.lib import cros_build_lib
 
 
-@command.CommandDecorator('chroot')
+@command.command_decorator('chroot')
 class ChrootCommand(command.CliCommand):
   """Enter the chroot."""
 
@@ -46,7 +46,6 @@
 
   def Run(self):
     """Runs `cros chroot`."""
-    self.options.Freeze()
     cmd = self.options.command
 
     # If -- was used to separate out the command from arguments, ignore it.
diff --git a/cli/cros/cros_cidbcreds.py b/cli/cros/cros_cidbcreds.py
index b339b64..057a2f5 100644
--- a/cli/cros/cros_cidbcreds.py
+++ b/cli/cros/cros_cidbcreds.py
@@ -53,7 +53,7 @@
       shutil.rmtree(cidb_dir, ignore_errors=True)
       raise
 
-@command.CommandDecorator('cidbcreds')
+@command.command_decorator('cidbcreds')
 class CidbCredsCommand(command.CliCommand):
   """cros cidbcreds: download the prod_replica_cidb_readonly credentials."""
 
@@ -68,7 +68,6 @@
 
   def Run(self):
     """Run cros cidbcreds."""
-    self.options.Freeze()
     cidb_dir = CheckAndGetCIDBCreds(force_update=self.options.force_update,
                                     folder=self.options.folder)
     logging.notice('CIDB credentials at: %s', cidb_dir)
diff --git a/cli/cros/cros_clean.py b/cli/cros/cros_clean.py
index cc1b28b..7d12914 100644
--- a/cli/cros/cros_clean.py
+++ b/cli/cros/cros_clean.py
@@ -21,9 +21,10 @@
 from chromite.lib import cros_build_lib
 from chromite.lib import dev_server_wrapper
 from chromite.lib import osutils
+from chromite.utils import timer
 
 
-@command.CommandDecorator('clean')
+@command.command_decorator('clean')
 class CleanCommand(command.CliCommand):
   """Clean up working files from the build."""
 
@@ -126,8 +127,7 @@
     group.add_argument(
         '--sdk-path',
         type='path',
-        default=os.path.join(constants.SOURCE_ROOT,
-                             constants.DEFAULT_CHROOT_DIR),
+        default=constants.DEFAULT_CHROOT_PATH,
         help='The sdk (chroot) path. This only needs to be provided if your '
              'chroot is not in the default location.')
 
@@ -135,44 +135,46 @@
     """Initializes cros clean."""
     command.CliCommand.__init__(self, options)
 
+  @classmethod
+  def ProcessOptions(cls, parser, options):
+    """Post process options."""
+    # If no option is set, default to "--safe".
+    if not (options.autotest or
+            options.board or
+            options.cache or
+            options.chromite or
+            options.chroot or
+            options.chroot_tmp or
+            options.clobber or
+            options.deploy or
+            options.flash or
+            options.images or
+            options.incrementals or
+            options.logs or
+            options.safe or
+            options.sysroots or
+            options.workdirs):
+      options.safe = True
+
+    if options.clobber:
+      options.chroot = True
+      options.autotest = True
+      options.safe = True
+
+    if options.safe:
+      options.cache = True
+      options.chromite = True
+      options.chroot_tmp = True
+      options.deploy = True
+      options.flash = True
+      options.images = True
+      options.incrementals = True
+      options.logs = True
+      options.workdirs = True
+
+  @timer.timed('Cros Clean', logging.debug)
   def Run(self):
     """Perform the cros clean command."""
-    # If no option is set, default to "--safe"
-    if not (self.options.autotest or
-            self.options.board or
-            self.options.cache or
-            self.options.chromite or
-            self.options.chroot or
-            self.options.chroot_tmp or
-            self.options.clobber or
-            self.options.deploy or
-            self.options.flash or
-            self.options.images or
-            self.options.incrementals or
-            self.options.logs or
-            self.options.safe or
-            self.options.sysroots or
-            self.options.workdirs):
-      self.options.safe = True
-
-    if self.options.clobber:
-      self.options.chroot = True
-      self.options.autotest = True
-      self.options.safe = True
-
-    if self.options.safe:
-      self.options.cache = True
-      self.options.chromite = True
-      self.options.chroot_tmp = True
-      self.options.deploy = True
-      self.options.flash = True
-      self.options.images = True
-      self.options.incrementals = True
-      self.options.logs = True
-      self.options.workdirs = True
-
-    self.options.Freeze()
-
     chroot_dir = self.options.sdk_path
 
     cros_build_lib.AssertOutsideChroot()
@@ -207,7 +209,8 @@
       if self.options.dry_run:
         logging.notice('would have cleaned: %s', chroot_dir)
       else:
-        cros_build_lib.run(['cros_sdk', '--delete'])
+        with timer.timer('Remove the chroot', logging.debug):
+          cros_build_lib.run(['cros_sdk', '--delete'])
 
     boards = self.options.board or []
     if self.options.sysroots:
@@ -216,17 +219,22 @@
       except OSError as e:
         if e.errno != errno.ENOENT:
           raise
-    for b in boards:
-      logging.debug('Clean up the %s sysroot.', b)
-      Clean(os.path.join(chroot_dir, 'build', b))
+    if boards:
+      with timer.timer('Clean Sysroots', logging.debug):
+        for b in boards:
+          logging.debug('Clean up the %s sysroot.', b)
+          with timer.timer(f'Clean up the {b} sysroot.', logging.debug):
+            Clean(os.path.join(chroot_dir, 'build', b))
 
     if self.options.chroot_tmp:
       logging.debug('Empty chroot tmp directory.')
-      Empty(os.path.join(chroot_dir, 'tmp'))
+      with timer.timer('Empty chroot tmp directory', logging.debug):
+        Empty(os.path.join(chroot_dir, 'tmp'))
 
     if self.options.cache:
       logging.debug('Clean the common cache.')
-      CleanNoBindMount(self.options.cache_dir)
+      with timer.timer('Clean the common cache', logging.debug):
+        CleanNoBindMount(self.options.cache_dir)
 
       # Recreate dirs that cros_sdk does when entering.
       # TODO: When sdk_lib/enter_chroot.sh is moved to chromite, we should unify
@@ -240,50 +248,62 @@
 
     if self.options.chromite:
       logging.debug('Clean chromite workdirs.')
-      Clean(os.path.join(constants.CHROMITE_DIR, 'venv', 'venv'))
-      Clean(os.path.join(constants.CHROMITE_DIR, 'venv', '.venv_lock'))
+      with timer.timer('Clean chromite workdirs', logging.debug):
+        Clean(os.path.join(constants.CHROMITE_DIR, 'venv', 'venv'))
+        Clean(os.path.join(constants.CHROMITE_DIR, 'venv', '.venv_lock'))
 
     if self.options.deploy:
       logging.debug('Clean up the cros deploy cache.')
-      for subdir in ('custom-packages', 'gmerge-packages'):
-        for d in glob.glob(os.path.join(chroot_dir, 'build', '*', subdir)):
-          Clean(d)
+      with timer.timer('Clean up the cros deploy cache', logging.debug):
+        for subdir in ('custom-packages', 'gmerge-packages'):
+          for d in glob.glob(os.path.join(chroot_dir, 'build', '*', subdir)):
+            Clean(d)
 
     if self.options.flash:
       if self.options.dry_run:
         _LogClean(dev_server_wrapper.DEFAULT_STATIC_DIR)
       else:
-        dev_server_wrapper.DevServerWrapper.WipeStaticDirectory()
+        with timer.timer(dev_server_wrapper.DEFAULT_STATIC_DIR, logging.debug):
+          dev_server_wrapper.DevServerWrapper.WipeStaticDirectory()
 
     if self.options.images:
       logging.debug('Clean the images cache.')
       cache_dir = os.path.join(constants.SOURCE_ROOT, 'src', 'build')
-      CleanNoBindMount(cache_dir)
+      with timer.timer('Clean the images cache', logging.debug):
+        CleanNoBindMount(cache_dir)
 
     if self.options.incrementals:
       logging.debug('Clean package incremental objects.')
-      Empty(os.path.join(chroot_dir, 'var', 'cache', 'portage'))
-      for d in glob.glob(
-          os.path.join(chroot_dir, 'build', '*', 'var', 'cache', 'portage')):
-        Empty(d)
+      with timer.timer('Clean package incremental objects', logging.debug):
+        Empty(os.path.join(chroot_dir, 'var', 'cache', 'portage'))
+        for d in glob.glob(
+            os.path.join(chroot_dir, 'build', '*', 'var', 'cache', 'portage')):
+          Empty(d)
+        for d in glob.glob(
+            os.path.join(chroot_dir, 'var', 'cache', 'chromeos-chrome', '*',
+                         'src', 'out_*')):
+          Clean(d)
 
     if self.options.logs:
       logging.debug('Clean log files.')
-      Empty(os.path.join(chroot_dir, 'var', 'log'))
-      for d in glob.glob(
-          os.path.join(chroot_dir, 'build', '*', 'tmp', 'portage', 'logs')):
-        Empty(d)
+      with timer.timer('Clean log files', logging.debug):
+        Empty(os.path.join(chroot_dir, 'var', 'log'))
+        for d in glob.glob(
+            os.path.join(chroot_dir, 'build', '*', 'tmp', 'portage', 'logs')):
+          Empty(d)
 
     if self.options.workdirs:
       logging.debug('Clean package workdirs.')
-      Clean(os.path.join(chroot_dir, 'var', 'tmp', 'portage'))
-      Clean(os.path.join(constants.CHROMITE_DIR, 'venv', 'venv'))
-      for d in glob.glob(
-          os.path.join(chroot_dir, 'build', '*', 'tmp', 'portage')):
-        Clean(d)
+      with timer.timer('Clean package workdirs', logging.debug):
+        Clean(os.path.join(chroot_dir, 'var', 'tmp', 'portage'))
+        Clean(os.path.join(constants.CHROMITE_DIR, 'venv', 'venv'))
+        for d in glob.glob(
+            os.path.join(chroot_dir, 'build', '*', 'tmp', 'portage')):
+          Clean(d)
 
     if self.options.autotest:
       logging.debug('Clean build_externals.')
-      packages_dir = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
-                                  'autotest', 'files', 'site-packages')
-      Clean(packages_dir)
+      with timer.timer('Clean build_externals', logging.debug):
+        packages_dir = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
+                                    'autotest', 'files', 'site-packages')
+        Clean(packages_dir)
diff --git a/cli/cros/cros_debug.py b/cli/cros/cros_debug.py
index 997eead..bbb9ac4 100644
--- a/cli/cros/cros_debug.py
+++ b/cli/cros/cros_debug.py
@@ -13,7 +13,7 @@
 from chromite.lib import remote_access
 
 
-@command.CommandDecorator('debug')
+@command.command_decorator('debug')
 class DebugCommand(command.CliCommand):
   """Use GDB to debug a process running on the target device.
 
@@ -74,6 +74,18 @@
         '-p', '--pid', type=int,
         help='The pid of the process on the target device.')
 
+  @classmethod
+  def ProcessOptions(cls, parser, options):
+    """Post process options."""
+    if not (options.pid or options.exe):
+      parser.error('Must use --exe or --pid to specify the process to debug.')
+
+    if options.pid and (options.list or options.exe):
+      parser.error('--list and --exe are disallowed when --pid is used.')
+
+    if not options.exe.startswith('/'):
+      parser.error('--exe must have a full pathname.')
+
   def _ListProcesses(self, device, pids):
     """Provided with a list of pids, print out information of the processes."""
     if not pids:
@@ -122,7 +134,6 @@
   def Run(self):
     """Run cros debug."""
     commandline.RunInsideChroot(self)
-    self.options.Freeze()
     self._ReadOptions()
     with remote_access.ChromiumOSDeviceHandler(
         self.ssh_hostname, port=self.ssh_port, username=self.ssh_username,
@@ -140,19 +151,10 @@
       if self.ssh_port:
         self.gdb_cmd.extend(['--ssh_port', str(self.ssh_port)])
 
-      if not (self.pid or self.exe):
-        cros_build_lib.Die(
-            'Must use --exe or --pid to specify the process to debug.')
-
       if self.pid:
-        if self.list or self.exe:
-          cros_build_lib.Die(
-              '--list and --exe are disallowed when --pid is used.')
         self._DebugRunningProcess(self.pid)
         return
 
-      if not self.exe.startswith('/'):
-        cros_build_lib.Die('--exe must have a full pathname.')
       logging.debug('Executable path is %s', self.exe)
       if not device.IsFileExecutable(self.exe):
         cros_build_lib.Die(
diff --git a/cli/cros/cros_debug_unittest.py b/cli/cros/cros_debug_unittest.py
index e83f70f..0d6f63f 100644
--- a/cli/cros/cros_debug_unittest.py
+++ b/cli/cros/cros_debug_unittest.py
@@ -52,22 +52,26 @@
   def testMissingExeAndPid(self):
     """Test that command fails when --exe and --pid are not provided."""
     self.SetupCommandMock([self.DEVICE])
-    self.assertRaises(cros_build_lib.DieSystemExit, self.cmd_mock.inst.Run)
+    self.assertRaises(SystemExit, self.cmd_mock.inst.ProcessOptions,
+                      self.cmd_mock.parser, self.cmd_mock.inst.options)
 
   def testListDisallowedWithPid(self):
     """Test that --list is disallowed when --pid is used."""
     self.SetupCommandMock([self.DEVICE, '--list', '--pid', self.PID])
-    self.assertRaises(cros_build_lib.DieSystemExit, self.cmd_mock.inst.Run)
+    self.assertRaises(SystemExit, self.cmd_mock.inst.ProcessOptions,
+                      self.cmd_mock.parser, self.cmd_mock.inst.options)
 
   def testExeDisallowedWithPid(self):
     """Test that --exe is disallowed when --pid is used."""
     self.SetupCommandMock([self.DEVICE, '--exe', self.EXE, '--pid', self.PID])
-    self.assertRaises(cros_build_lib.DieSystemExit, self.cmd_mock.inst.Run)
+    self.assertRaises(SystemExit, self.cmd_mock.inst.ProcessOptions,
+                      self.cmd_mock.parser, self.cmd_mock.inst.options)
 
   def testExeMustBeFullPath(self):
     """Test that --exe only takes full path as a valid argument."""
     self.SetupCommandMock([self.DEVICE, '--exe', 'bash'])
-    self.assertRaises(cros_build_lib.DieSystemExit, self.cmd_mock.inst.Run)
+    self.assertRaises(SystemExit, self.cmd_mock.inst.ProcessOptions,
+                      self.cmd_mock.parser, self.cmd_mock.inst.options)
 
   def testDebugProcessWithPid(self):
     """Test that methods are called correctly when pid is provided."""
diff --git a/cli/cros/cros_deploy.py b/cli/cros/cros_deploy.py
index 5e1a3f6..31832bb 100644
--- a/cli/cros/cros_deploy.py
+++ b/cli/cros/cros_deploy.py
@@ -11,7 +11,7 @@
 from chromite.lib import commandline
 
 
-@command.CommandDecorator('deploy')
+@command.command_decorator('deploy')
 class DeployCommand(command.CliCommand):
   """Deploy the requested packages to the target device.
 
@@ -97,7 +97,6 @@
   def Run(self):
     """Run cros deploy."""
     commandline.RunInsideChroot(self)
-    self.options.Freeze()
     deploy.Deploy(
         self.options.device,
         self.options.packages,
diff --git a/cli/cros/cros_flash.py b/cli/cros/cros_flash.py
index d5a647d..964b14a 100644
--- a/cli/cros/cros_flash.py
+++ b/cli/cros/cros_flash.py
@@ -10,13 +10,12 @@
 from chromite.cli import flash
 from chromite.cli.cros import cros_chrome_sdk
 from chromite.lib import commandline
-from chromite.lib import cros_build_lib
 from chromite.lib import dev_server_wrapper
 from chromite.lib import path_util
-from chromite.utils import pformat
+from chromite.utils import timer
 
 
-@command.CommandDecorator('flash')
+@command.command_decorator('flash')
 class FlashCommand(command.CliCommand):
   """Update the device with an image.
 
@@ -187,10 +186,8 @@
 
   def Run(self):
     """Perform the cros flash command."""
-    self.options.Freeze()
-
     try:
-      with cros_build_lib.TimedSection() as timer:
+      with timer.Timer() as t:
         flash.Flash(
             self.options.device,
             self.options.image,
@@ -205,13 +202,12 @@
             ssh_private_key=self.options.private_key,
             ping=self.options.ping,
             disable_rootfs_verification=
-              self.options.disable_rootfs_verification,
+            self.options.disable_rootfs_verification,
             clear_cache=self.options.clear_cache,
             yes=self.options.yes,
             force=self.options.force,
             debug=self.options.debug)
-      logging.notice('cros flash completed successfully in %s',
-                     pformat.timedelta(timer.delta))
+      logging.notice('cros flash completed successfully in %s', t)
     except dev_server_wrapper.ImagePathError:
       logging.error('To get the latest remote image, please run:\n'
                     'cros flash --board=%s %s remote/latest',
diff --git a/cli/cros/cros_lint.py b/cli/cros/cros_lint.py
index f752968..4c7f078 100644
--- a/cli/cros/cros_lint.py
+++ b/cli/cros/cros_lint.py
@@ -4,6 +4,7 @@
 
 """Run lint checks on the specified files."""
 
+import fnmatch
 import functools
 import json
 import logging
@@ -11,7 +12,6 @@
 import os
 import re
 import sys
-import urllib.parse
 
 from chromite.cli import command
 from chromite.lib import constants
@@ -101,6 +101,14 @@
     'parseable': 'emacs',
 }
 
+# Default category filters to pass to cpplint.py when invoked via `cros lint`.
+#
+# `-foo/bar` means "don't show any lints from category foo/bar".
+# See `cpplint.py --help` for more explanation of category filters.
+CPPLINT_DEFAULT_FILTERS = (
+    '-runtime/references',
+)
+
 
 # The mapping between the "cros lint" --output-format flag and shellcheck
 # flags.
@@ -155,6 +163,7 @@
 def _CpplintFile(path, output_format, debug):
   """Returns result of running cpplint on |path|."""
   cmd = [os.path.join(constants.DEPOT_TOOLS_DIR, 'cpplint.py')]
+  cmd.append('--filter=%s' % ','.join(CPPLINT_DEFAULT_FILTERS))
   if output_format != 'default':
     cmd.append('--output=%s' % CPPLINT_OUTPUT_FORMAT_MAP[output_format])
   cmd.append(path)
@@ -285,29 +294,6 @@
 
   lint_result = _LinterRunCommand(cmd, debug)
 
-  # During testing, we don't want to fail the linter for shellcheck errors,
-  # so override the return code.
-  if lint_result.returncode != 0:
-    bug_url = (
-        'https://bugs.chromium.org/p/chromium/issues/entry?' +
-        urllib.parse.urlencode({
-            'template':
-                'Defect report from Developer',
-            'summary':
-                'Bad shellcheck warnings for %s' % os.path.basename(path),
-            'components':
-                'Infra>Client>ChromeOS>Build,',
-            'cc':
-                'bmgordon@chromium.org,vapier@chromium.org',
-            'comment':
-                'Shellcheck output from file:\n%s\n\n<paste output here>\n\n'
-                "What is wrong with shellcheck's findings?\n" % path,
-        }))
-    logging.warning('Shellcheck found problems. These will eventually become '
-                    'errors.  If the shellcheck findings are not useful, '
-                    'please file a bug at:\n%s', bug_url)
-    lint_result.returncode = 0
-
   # Check whitespace.
   if not _WhiteSpaceLintData(path, osutils.ReadFile(path)):
     lint_result.returncode = 1
@@ -322,12 +308,23 @@
 
 def _SeccompPolicyLintFile(path, _output_format, debug):
   """Run the seccomp policy linter."""
+  dangerous_syscalls = {'bpf', 'setns', 'execveat', 'ptrace', 'swapoff',
+                        'swapon'}
   return _LinterRunCommand(
       [os.path.join(constants.SOURCE_ROOT, 'src', 'aosp', 'external',
-                    'minijail', 'tools', 'seccomp_policy_lint.py'), path],
+                    'minijail', 'tools', 'seccomp_policy_lint.py'),
+       '--dangerous-syscalls', ','.join(dangerous_syscalls),
+       path],
       debug)
 
 
+def _DirMdLintFile(path, _output_format, debug):
+  """Run the dirmd linter."""
+  return _LinterRunCommand(
+      [os.path.join(constants.DEPOT_TOOLS_DIR, 'dirmd'), 'validate', path],
+      debug, capture_output=not debug)
+
+
 def _BreakoutDataByLinter(map_to_return, path):
   """Maps a linter method to the content of the |path|."""
   # Detect by content of the file itself.
@@ -371,6 +368,11 @@
     frozenset({'.policy'}): _SeccompPolicyLintFile,
 }
 
+# Map known filenames to a linter function.
+_FILENAME_PATTERNS_TO_LINTER_MAP = {
+    frozenset({'DIR_METADATA'}): _DirMdLintFile,
+}
+
 
 def _BreakoutFilesByLinter(files):
   """Maps a linter method to the list of files to lint."""
@@ -379,12 +381,17 @@
     extension = os.path.splitext(f)[1]
     for extensions, linter in _EXT_TO_LINTER_MAP.items():
       if extension in extensions:
-        todo = map_to_return.setdefault(linter, [])
-        todo.append(f)
+        map_to_return.setdefault(linter, []).append(f)
         break
     else:
-      if os.path.isfile(f):
-        _BreakoutDataByLinter(map_to_return, f)
+      name = os.path.basename(f)
+      for patterns, linter in _FILENAME_PATTERNS_TO_LINTER_MAP.items():
+        if any(fnmatch.fnmatch(name, x) for x in patterns):
+          map_to_return.setdefault(linter, []).append(f)
+          break
+      else:
+        if os.path.isfile(f):
+          _BreakoutDataByLinter(map_to_return, f)
 
   return map_to_return
 
@@ -397,7 +404,7 @@
       errors.value += 1
 
 
-@command.CommandDecorator('lint')
+@command.command_decorator('lint')
 class LintCommand(command.CliCommand):
   """Run lint checks on the specified files."""
 
@@ -428,7 +435,7 @@
       # they are aware that nothing was linted.
       logging.warning('No files provided to lint.  Doing nothing.')
 
-    errors = multiprocessing.Value('i')
+    errors = parallel.WrapMultiprocessing(multiprocessing.Value, 'i')
     linter_map = _BreakoutFilesByLinter(files)
     dispatcher = functools.partial(_Dispatcher, errors,
                                    self.options.output, self.options.debug)
diff --git a/cli/cros/cros_moblabvm.py b/cli/cros/cros_moblabvm.py
index 9ac782f..924fde5 100644
--- a/cli/cros/cros_moblabvm.py
+++ b/cli/cros/cros_moblabvm.py
@@ -25,7 +25,7 @@
 from chromite.lib import osutils
 
 
-@command.CommandDecorator('moblabvm')
+@command.command_decorator('moblabvm')
 class MoblabvmCommand(command.CliCommand):
   """Manage a moblab VM setup."""
 
@@ -111,7 +111,6 @@
 
   def Run(self):
     """The main handler of this CLI."""
-    self.options.Freeze()
     cmd = self.options.moblabvm_command
     if cmd == 'create':
       # Allow the workspace to not exist. This makes the CLI uniform across the
diff --git a/cli/cros/cros_shell.py b/cli/cros/cros_shell.py
index a7e2709..117888c 100644
--- a/cli/cros/cros_shell.py
+++ b/cli/cros/cros_shell.py
@@ -12,7 +12,7 @@
 from chromite.lib import remote_access
 
 
-@command.CommandDecorator('shell')
+@command.command_decorator('shell')
 class ShellCommand(command.CliCommand):
   """Opens a remote shell over SSH on the target device.
 
@@ -165,7 +165,6 @@
 
   def Run(self):
     """Runs `cros shell`."""
-    self.options.Freeze()
     self._ReadOptions()
     try:
       return self._StartSsh()
diff --git a/cli/cros/cros_stage.py b/cli/cros/cros_stage.py
index ca160f0..70d2a9f 100644
--- a/cli/cros/cros_stage.py
+++ b/cli/cros/cros_stage.py
@@ -48,7 +48,7 @@
                   r'(?P<build_name>R\d+-[\d.ab-]+)', gsurl)
 
 
-@command.CommandDecorator('stage')
+@command.command_decorator('stage')
 class StageCommand(command.CliCommand):
   """Remotely stages an image onto a MobLab device or into Google Storage.
 
diff --git a/cli/cros/cros_tryjob.py b/cli/cros/cros_tryjob.py
index 02a0cf8..935a747 100644
--- a/cli/cros/cros_tryjob.py
+++ b/cli/cros/cros_tryjob.py
@@ -351,28 +351,7 @@
     print('Tryjob submitted!')
     print('To view your tryjobs, visit:')
     for r in results:
-      print('{}{}'.format(constants.CHROMEOS_MILO_HOST,
-                                           r.id))
-
-
-def AdjustOptions(options):
-  """Set defaults that require some logic.
-
-  Args:
-    options: Parsed cros tryjob tryjob arguments.
-    site_config: config_lib.SiteConfig containing all config info.
-  """
-  if options.where == CBUILDBOT:
-    options.buildroot = options.buildroot or os.path.join(
-        os.path.dirname(constants.SOURCE_ROOT), 'cbuild')
-
-  if options.where == LOCAL:
-    options.buildroot = options.buildroot or os.path.join(
-        os.path.dirname(constants.SOURCE_ROOT), 'tryjob')
-
-  if options.buildroot:
-    options.git_cache_dir = options.git_cache_dir or os.path.join(
-        options.buildroot, '.git_cache')
+      print(f'{constants.CHROMEOS_MILO_HOST}{r.id}')
 
 
 def VerifyOptions(options, site_config):
@@ -471,7 +450,7 @@
                          'pool (given %s).' % options.hwtest_dut_dimensions)
 
 
-@command.CommandDecorator('tryjob')
+@command.command_decorator('tryjob')
 class TryjobCommand(command.CliCommand):
   """Schedule a tryjob."""
 
@@ -630,12 +609,12 @@
         '--hwtest', dest='passthrough', action='append_option',
         help='Enable hwlab testing. Default false.')
     test_group.add_argument(
-      '--hwtest_dut_dimensions', action='split_extend', default=None,
-      help='Space-separated list of key:val Swarming bot '
-           'dimensions to run each builders SkylabHWTest '
-           'stages against (this overrides the configured '
-           'DUT dimensions for each test). Requires at least '
-           '"label-board", "label-model", and "label-pool".')
+        '--hwtest_dut_dimensions', action='split_extend', default=None,
+        help='Space-separated list of key:val Swarming bot '
+             'dimensions to run each builders SkylabHWTest '
+             'stages against (this overrides the configured '
+             'DUT dimensions for each test). Requires at least '
+             '"label-board", "label-model", and "label-pool".')
     test_group.add_argument(
         '--notests', dest='passthrough', action='append_option',
         help='Override values from buildconfig, run no '
@@ -668,12 +647,25 @@
         '-l', '--list', action='store_true', dest='list', default=False,
         help='List the trybot configs (adjusted by --production).')
 
+  @classmethod
+  def ProcessOptions(cls, parser, options):
+    """Post process options."""
+    if options.where == CBUILDBOT:
+      options.buildroot = options.buildroot or os.path.join(
+          os.path.dirname(constants.SOURCE_ROOT), 'cbuild')
+
+    if options.where == LOCAL:
+      options.buildroot = options.buildroot or os.path.join(
+          os.path.dirname(constants.SOURCE_ROOT), 'tryjob')
+
+    if options.buildroot:
+      options.git_cache_dir = options.git_cache_dir or os.path.join(
+          options.buildroot, '.git_cache')
+
   def Run(self):
     """Runs `cros tryjob`."""
     site_config = config_lib.GetConfig()
 
-    AdjustOptions(self.options)
-    self.options.Freeze()
     VerifyOptions(self.options, site_config)
 
     logging.info('Verifying patches...')
diff --git a/cli/cros/cros_tryjob_unittest.py b/cli/cros/cros_tryjob_unittest.py
index d9e3ef2..cb00f77 100644
--- a/cli/cros/cros_tryjob_unittest.py
+++ b/cli/cros/cros_tryjob_unittest.py
@@ -285,15 +285,15 @@
     self.assertGreaterEqual(vars(options).items(), self.expected.items())
 
 
-class TryjobTestAdjustOptions(TryjobTest):
-  """Test cros_tryjob.AdjustOptions."""
+class TryjobTestProcessOptions(TryjobTest):
+  """Test cros_tryjob.TryjobCommand.ProcessOptions."""
 
   def testRemote(self):
     """Test default remote buildroot."""
     self.SetupCommandMock(['config'])
     options = self.cmd_mock.inst.options
 
-    cros_tryjob.AdjustOptions(options)
+    cros_tryjob.TryjobCommand.ProcessOptions(None, options)
 
     self.assertIsNone(options.buildroot)
     self.assertIsNone(options.git_cache_dir)
@@ -303,7 +303,7 @@
     self.SetupCommandMock(['--local', 'config'])
     options = self.cmd_mock.inst.options
 
-    cros_tryjob.AdjustOptions(options)
+    cros_tryjob.TryjobCommand.ProcessOptions(None, options)
 
     self.assertTrue(options.buildroot.endswith('/tryjob'))
     self.assertTrue(options.git_cache_dir.endswith('/tryjob/.git_cache'))
@@ -316,7 +316,7 @@
                            'config'])
     options = self.cmd_mock.inst.options
 
-    cros_tryjob.AdjustOptions(options)
+    cros_tryjob.TryjobCommand.ProcessOptions(None, options)
 
     self.assertEqual(options.buildroot, '/buildroot')
     self.assertEqual(options.git_cache_dir, '/git-cache')
@@ -326,7 +326,7 @@
     self.SetupCommandMock(['--cbuildbot', 'config'])
     options = self.cmd_mock.inst.options
 
-    cros_tryjob.AdjustOptions(options)
+    cros_tryjob.TryjobCommand.ProcessOptions(None, options)
 
     self.assertTrue(options.buildroot.endswith('/cbuild'))
     self.assertTrue(options.git_cache_dir.endswith('/cbuild/.git_cache'))
@@ -339,7 +339,7 @@
                            'config'])
     options = self.cmd_mock.inst.options
 
-    cros_tryjob.AdjustOptions(options)
+    cros_tryjob.TryjobCommand.ProcessOptions(None, options)
 
     self.assertEqual(options.buildroot, '/buildroot')
     self.assertEqual(options.git_cache_dir, '/git-cache')
@@ -562,8 +562,8 @@
   def testInvalidHWTestDUTDimensions(self):
     """Test option verification with invalid hw_test_dut_dimensions."""
     self.SetupCommandMock([
-      '--hwtest_dut_dimensions',
-      'label-board:foo-board label-model:foo-model label-pol:foo-typo'])
+        '--hwtest_dut_dimensions',
+        'label-board:foo-board label-model:foo-model label-pol:foo-typo'])
 
     with self.assertRaises(cros_build_lib.DieSystemExit):
       cros_tryjob.VerifyOptions(self.cmd_mock.inst.options, self.site_config)
@@ -612,7 +612,7 @@
     """
     self.SetupCommandMock(args_in)
     options = self.cmd_mock.inst.options
-    cros_tryjob.AdjustOptions(options)
+    cros_tryjob.TryjobCommand.ProcessOptions(None, options)
     args_out = cros_tryjob.CbuildbotArgs(options)
     return args_out
 
diff --git a/cli/cros/cros_uprevchrome.py b/cli/cros/cros_uprevchrome.py
deleted file mode 100644
index eec809a..0000000
--- a/cli/cros/cros_uprevchrome.py
+++ /dev/null
@@ -1,86 +0,0 @@
-# Copyright 2016 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""cros uprevchrome: Uprev chrome to a new valid version."""
-
-from chromite.cli import command
-from chromite.lib import cros_build_lib
-
-
-@command.CommandDecorator('uprevchrome')
-class UprevChromeCommand(command.CliCommand):
-  """cros uprevchrome: Uprev chrome to a new valid version
-
-  When a chrome PFQ failure happens, master_chrome_pfq automatically checks the
-  status of certain stages and then uploads the ebuild/binhost_mapping
-  updates to a staging branch in remote git repository. This tool provides a way
-  to fetch the updates from the remote staging branch, generate CLs to manually
-  uprev chrome and upload the CLs to Gerrit for review.
-
-  Users need to provide a failed master_chrome_pfq build_id, the bug id to track
-  this manual uprev. This tool first verifies if the build_id is valid and if
-  the staging branches exist, then fetches the changes into local branches,
-  updates commit messages, adds CQ-DEPEND, rebases based on master and uploads
-  CLs to Gerrit.
-
-  Examples:
-    cros uprevchrome --pfq-build XXXX --bug='chromium:XXXXX'
-        [--dry-run] [--debug] [--nowipe] [--draft]
-
-  After successfully executing this tool, review and submit CLs from Gerrit.
-  https://chromium-review.googlesource.com
-  https://chrome-internal-review.googlesource.com/
-
-  Note:
-  A master Chrome PFQ build id argument is required. It must satisfy the
-  following requirements:
-    * If you are a gardener trying to uprev Chrome please verify if the Chrome
-      version you are trying to uprev to is stable and not crashy. Please
-      communicate with the corresponding Chrome TPM to find out if that Chrome
-      has any known issues or is particularly crashy. If yes, please work with
-      them to find a stable Chrome that can be used to uprev.
-    * The current  Chrome PFQ run is a failed run;
-    * No successful Chrome PFQ runs after this Chrome PFQ run;
-    * Master build of this PFQ run must have passed BinhostTest stage;
-    * All important slave builds of this PFQ run must have passed
-      UploadPrebuiltsTest stage.
-    * A bug id is required to track each manual uprev, describing the known
-      source of flake that is responsible for this run's failure.
-  The public CL and private CL depend on each other,
-  please submit them together.
-  Please do not revert the generated CLs after they're merged.
-  Please use cros_pinchrome to pin/unpin Chrome if needed.
-  A detailed guide here:
-  http://g3doc/company/teams/chrome/ops/chromeos/continuous_integration/on-call/guides/cros_uprevchrome_guide
-  """
-
-  @classmethod
-  def AddParser(cls, parser):
-    super(cls, UprevChromeCommand).AddParser(parser)
-    parser.add_argument('--pfq-build', action='store',
-                        metavar='PFQ_BUILD',
-                        help='The buildbucket_id of the master chrome pfq'
-                        ' build. Note this is a 19 digit ID that can be found'
-                        'in the Milo or GoldenEye URL for the build.')
-    parser.add_argument('--fake-buildstore', action='store', default=False,
-                        help='Use a FakeBuildStore instance')
-    parser.add_argument('--bug', action='store',
-                        help='Used in the "BUG" field of CLs.')
-    parser.add_argument('--nowipe', default=True, dest='wipe',
-                        action='store_false',
-                        help='Preserve the working directory.')
-    parser.add_argument('--draft', action='store_true',
-                        help='Upload the uprev CLs to Gerrit as drafts.')
-    parser.add_argument('--dry-run', action='store_true',
-                        help="Prepare CLs but don't upload them to Gerrit")
-    parser.add_argument('--reviewers',
-                        action='append', default=[],
-                        help='Add reviewers to the CLs.'
-                        'ex:--reviewer x@email.com --reviewer y@email.com')
-    return parser
-
-  def Run(self):
-    """Prints deprecation message."""
-    cros_build_lib.Die('***CROS UPREVCHROME HAS BEEN SUPERSEDED BY PUpr!***'
-                       '\n***Refer to go/cros-gardening and go/pupr***')
diff --git a/cli/cros/cros_workon.py b/cli/cros/cros_workon.py
index a9557cb..4ada40d 100644
--- a/cli/cros/cros_workon.py
+++ b/cli/cros/cros_workon.py
@@ -39,7 +39,7 @@
     '  %s%s' % (a[0].ljust(_fill, ' '), a[1]) for a in _ACTIONS)
 
 
-@command.CommandDecorator('workon')
+@command.command_decorator('workon')
 class WorkonCommand(command.CliCommand):
   """Forces rebuilds of worked on packages from the local source."""
 
@@ -129,15 +129,16 @@
 
     return parser
 
-  def Run(self):
-    if self.options.build_target_name:
-      self.options.build_target = build_target_lib.BuildTarget(
-          self.options.build_target_name)
+  @classmethod
+  def ProcessOptions(cls, parser, options):
+    """Post process options."""
+    if options.build_target_name:
+      options.build_target = build_target_lib.BuildTarget(
+          options.build_target_name)
     else:
-      self.options.build_target = None
+      options.build_target = None
 
-    self.options.Freeze()
-
+  def Run(self):
     has_target = self.options.host or self.options.build_target
     needs_target = self.options.action != 'list-all'
     if needs_target and not has_target:
diff --git a/cli/cros/lint.py b/cli/cros/lint.py
index 25d17ac..fa66b8c 100644
--- a/cli/cros/lint.py
+++ b/cli/cros/lint.py
@@ -24,20 +24,15 @@
 import re
 import sys
 
+import astroid
 import pylint.checkers
 from pylint.config import ConfigurationMixIn
 import pylint.interfaces
 
 from chromite.third_party.pylint import format_checkers
 from chromite.utils import memoize
-
-
-_THIRD_PARTY = os.path.join(
-    os.path.dirname(os.path.realpath(__file__)), '..', '..', 'third_party')
-_PYLINT_QUOTES = os.path.join(_THIRD_PARTY, 'pylint-quotes')
-sys.path.insert(0, _PYLINT_QUOTES)
-# pylint: disable=unused-import,wrong-import-position
-from pylint_quotes.checker import StringQuoteChecker
+# pylint: disable=unused-import
+from chromite.third_party.pylint_quotes.checker import StringQuoteChecker
 
 
 # pylint: disable=too-few-public-methods
@@ -560,58 +555,6 @@
       self.add_message('C9011', node=node, line=node.fromlineno, args=margs)
 
 
-class Py3kCompatChecker(pylint.checkers.BaseChecker):
-  """Make sure we enforce py3k compatible features"""
-
-  __implements__ = pylint.interfaces.IAstroidChecker
-
-  # pylint: disable=class-missing-docstring,multiple-statements
-  class _MessageR9100(object): pass
-  # pylint: enable=class-missing-docstring,multiple-statements
-
-  name = 'py3k_compat_checker'
-  priority = -1
-  MSG_ARGS = 'offset:%(offset)i: {%(line)s}'
-  msgs = {
-      'R9100': ('Missing "from __future__ import print_function" line',
-                ('missing-print-function'), _MessageR9100),
-  }
-  options = ()
-
-  def __init__(self, *args, **kwargs):
-    super().__init__(*args, **kwargs)
-    self.seen_print_func = False
-    self.saw_imports = False
-
-  def close(self):
-    """Called when done processing module"""
-    if not self.seen_print_func:
-      # Only enforce this on Python 2 files.
-      if sys.version_info.major >= 3:
-        return
-
-      # Do not warn if moduler doesn't import anything at all (like
-      # empty __init__.py files).
-      if self.saw_imports:
-        self.add_message('R9100')
-
-  def _check_print_function(self, node):
-    """Verify print_function is imported"""
-    if node.modname == '__future__':
-      for name, _ in node.names:
-        if name == 'print_function':
-          self.seen_print_func = True
-
-  def visit_importfrom(self, node):
-    """Process 'from' statements"""
-    self.saw_imports = True
-    self._check_print_function(node)
-
-  def visit_import(self, _node):
-    """Process 'import' statements"""
-    self.saw_imports = True
-
-
 class SourceChecker(pylint.checkers.BaseChecker):
   """Make sure we enforce rules on the source."""
 
@@ -770,6 +713,35 @@
         self._visit_comment(start_row, token)
 
 
+class FormatStringChecker(pylint.checkers.BaseChecker):
+  """Check string formatting."""
+
+  __implements__ = pylint.interfaces.IAstroidChecker
+
+  # pylint: disable=class-missing-docstring,multiple-statements
+  class _MessageR9100(object): pass
+  # pylint: enable=class-missing-docstring,multiple-statements
+
+  name = 'format_string_checker'
+  priority = -1
+  MSG_ARGS = 'offset:%(offset)i: {%(line)s}'
+  msgs = {
+      'R9100': ('Use f-strings or % interpolation, never .format()',
+                ('banned-string-format-function'), _MessageR9100),
+  }
+  options = ()
+
+  def visit_const(self, node: astroid.nodes.Const) -> None:
+    """Process a constant string node."""
+    if (node.pytype() == 'builtins.str' and
+        not isinstance(node.parent, astroid.nodes.JoinedStr) and
+        isinstance(node.parent, astroid.nodes.Attribute) and
+        node.parent.attrname == 'format' and
+        isinstance(node.parent.parent, astroid.nodes.Call)):
+      self.add_message('R9100', node=node, line=node.lineno,
+                       col_offset=node.col_offset)
+
+
 def register(linter):
   """pylint will call this func to register all our checkers"""
   # Walk all the classes in this module and register ours.
diff --git a/cli/cros/tests/cros_vm_test.py b/cli/cros/tests/cros_vm_test.py
index bed0410..f1ff037 100644
--- a/cli/cros/tests/cros_vm_test.py
+++ b/cli/cros/tests/cros_vm_test.py
@@ -10,7 +10,7 @@
 (sdk)$ ./build_image --board=betty test
 (sdk)$ cd ../../chromite/cli/cros/tests/
 (sdk)$ ./cros_vm_test --board=betty --image_path \
-~/trunk/src/build/images/betty/latest/chromiumos_test_image.bin
+~/chromiumos/src/build/images/betty/latest/chromiumos_test_image.bin
 """
 
 from chromite.cli import command_vm_test
diff --git a/cli/deploy.py b/cli/deploy.py
index 10801cd..077d7f8 100644
--- a/cli/deploy.py
+++ b/cli/deploy.py
@@ -20,6 +20,7 @@
 
 from chromite.cli import command
 from chromite.lib import build_target_lib
+from chromite.lib import constants
 from chromite.lib import cros_build_lib
 from chromite.lib import dlc_lib
 from chromite.lib import operation
@@ -898,7 +899,8 @@
   if strip:
     try:
       cros_build_lib.run(
-          ['strip_package', '--sysroot', sysroot] +
+          [os.path.join(constants.CHROMITE_SCRIPTS_DIR, 'strip_package'),
+           '--sysroot', sysroot] +
           [cpv.cpf for cpv in cpvs])
       packages_dir = _STRIPPED_PACKAGES_DIR
     except cros_build_lib.RunCommandError:
diff --git a/cli/deploy_unittest.py b/cli/deploy_unittest.py
index 33a5a8d..29357d5 100644
--- a/cli/deploy_unittest.py
+++ b/cli/deploy_unittest.py
@@ -18,6 +18,7 @@
 from chromite.lib import osutils
 from chromite.lib import remote_access
 from chromite.lib import sysroot_lib
+from chromite.lib import unittest_lib
 from chromite.lib.parser import package_info
 
 
@@ -331,6 +332,8 @@
     # Avoid running the portageq command.
     sysroot_lib.Sysroot(self._sysroot).WriteConfig(
         'ARCH="amd64"\nPORTDIR_OVERLAY="%s"' % '/nothing/here')
+    # make.conf needs to exist to correctly read back config.
+    unittest_lib.create_stub_make_conf(self._sysroot)
 
 
   def testDeployEmerge(self):
diff --git a/cli/device_imager.py b/cli/device_imager.py
index 1ad081b..a1eceb0 100644
--- a/cli/device_imager.py
+++ b/cli/device_imager.py
@@ -31,6 +31,7 @@
 from chromite.lib.paygen import paygen_stateful_payload_lib
 from chromite.lib.xbuddy import devserver_constants
 from chromite.lib.xbuddy import xbuddy
+from chromite.utils import timer
 
 
 class Error(Exception):
@@ -269,13 +270,19 @@
                                       None))
 
     if not self._no_minios_update:
-      # Reference disk_layout_v3 for partition numbering.
-      _, inactive_minios_state = self._GetMiniOSState(
-          9 if self._device.run(
-              ['crossystem', constants.MINIOS_PRIORITY]).output == 'A' else 10)
-      target_minios = prefix + str(inactive_minios_state[Partition.MINIOS])
-      updaters.append(MiniOSUpdater(self._device, self._image, self._image_type,
-                                    target_minios, self._compression))
+      minios_priority = self._device.run(
+          ['crossystem', constants.MINIOS_PRIORITY]).stdout
+      if minios_priority not in ['A', 'B']:
+        logging.warning('Skipping miniOS flash due to missing priority.')
+      else:
+        # Reference disk_layout_v3 for partition numbering.
+        _, inactive_minios_state = self._GetMiniOSState(
+            9 if minios_priority == 'A' else 10)
+        target_minios = prefix + str(inactive_minios_state[Partition.MINIOS])
+        minios_updater = MiniOSUpdater(self._device, self._image,
+                                       self._image_type, target_minios,
+                                       self._compression)
+        updaters.append(minios_updater)
 
     # Retry the partitions updates that failed, in case a transient error (like
     # SSH drop, etc) caused the error.
@@ -495,13 +502,13 @@
 
   def Run(self):
     """The main function that does the partition update job."""
-    with cros_build_lib.TimedSection() as timer:
+    with timer.Timer() as t:
       try:
         self._Run()
       finally:
         self._finished = True
 
-    logging.debug('Completed %s in %s', self.__class__.__name__, timer.delta)
+    logging.debug('Completed %s in %s', self.__class__.__name__, t)
 
   @abc.abstractmethod
   def _Run(self):
@@ -748,17 +755,29 @@
 
   def _GetRemotePartitionName(self):
     """See RawPartitionUpdater._GetRemotePartitionName()."""
-    # TODO(b/190631159, b/196056723): Allow fetching once miniOS payloads exist.
-    raise NotImplementedError("MiniOS payloads aren't uploaded yet.")
+    return constants.QUICK_PROVISION_PAYLOAD_MINIOS
 
   def _Run(self):
     """The function that does the job of rootfs partition update."""
-    if self._image_type in [ImageType.FULL, ImageType.REMOTE_DIRECTORY]:
-      if self._MiniOSPartitionExists():
-        logging.info('Updating miniOS partition.')
+    if self._image_type == ImageType.FULL:
+      if self._MiniOSPartitionsExistInImage():
+        logging.info('Updating miniOS partition from local.')
         super()._Run()
       else:
-        logging.info('Not updating miniOS partition as it does not exist.')
+        logging.warning('Not updating miniOS partition as it does not exist.')
+        return
+    elif self._image_type == ImageType.REMOTE_DIRECTORY:
+      if not gs.GSContext().Exists(
+          os.path.join(self._image,
+                       constants.QUICK_PROVISION_PAYLOAD_MINIOS)):
+        logging.warning('Not updating miniOS, missing remote files.')
+        return
+      elif not self._MiniOSPartitionsExist():
+        logging.warning('Not updating miniOS, missing partitions.')
+        return
+      else:
+        logging.info('Updating miniOS partition from remote.')
+        super()._Run()
     else:
       # Let super() handle this error.
       super()._Run()
@@ -787,19 +806,22 @@
     logging.info('Setting miniOS priority to %s', inactive_minios_priority)
     self._SetMiniOSPriority(inactive_minios_priority)
 
-  def _MiniOSPartitionExists(self):
-    """Checks if miniOS partition exists."""
-    if self._image_type == ImageType.FULL:
-      d = cgpt.Disk.FromImage(self._image)
-      try:
-        d.GetPartitionByTypeGuid(cgpt.MINIOS_TYPE_GUID)
-        return True
-      except KeyError:
-        return False
-    elif self._image_type == ImageType.REMOTE_DIRECTORY:
-      # TODO(b/190631159, b/196056723): Check miniOS payload in remote.
+  def _MiniOSPartitionsExistInImage(self):
+    """Checks if miniOS partition exists in the image."""
+    d = cgpt.Disk.FromImage(self._image)
+    try:
+      d.GetPartitionByTypeGuid(cgpt.MINIOS_TYPE_GUID)
+      return True
+    except KeyError:
       return False
 
+  def _MiniOSPartitionsExist(self):
+    """Checks if the device has miniOS partitions."""
+    run = lambda x: self._device.run(x).stdout.strip()
+    device_drive = run(['rootdev', '-s', '-d'])
+    cmd = ['cgpt', 'show', '-t', device_drive, '-i']
+    return all((run(cmd + [p]) == cgpt.MINIOS_TYPE_GUID) for p in ('9', '10'))
+
 
 class StatefulPayloadGenerator(ReaderBase):
   """A class for generating a stateful update payload in a separate thread."""
diff --git a/cli/device_imager_unittest.py b/cli/device_imager_unittest.py
index c5606b4..21dcba4 100644
--- a/cli/device_imager_unittest.py
+++ b/cli/device_imager_unittest.py
@@ -190,7 +190,7 @@
   def testRun(self):
     """Tests the main run() function."""
     with device_imager.PartialFileReader(
-          '/foo', 512 * 2, 512, cros_build_lib.COMP_GZIP) as pfr:
+        '/foo', 512 * 2, 512, cros_build_lib.COMP_GZIP) as pfr:
       pass
 
     self.assertCommandCalled(
@@ -264,8 +264,9 @@
       self.rsh_mock.AddCmdResult([partial_mock.In('which'), 'gzip'],
                                  returncode=0)
       self.rsh_mock.AddCmdResult(
-        self.path_env +
-        ' gzip --decompress --stdout | dd bs=1M oflag=direct of=/dev/mmcblk0p2')
+          self.path_env +
+          ' gzip --decompress --stdout | ' +
+          'dd bs=1M oflag=direct of=/dev/mmcblk0p2')
 
       device_imager.RawPartitionUpdater(
           device, 'foo-image', device_imager.ImageType.FULL,
@@ -280,8 +281,9 @@
       self.rsh_mock.AddCmdResult([partial_mock.In('which'), 'gzip'],
                                  returncode=0)
       self.rsh_mock.AddCmdResult(
-        self.path_env +
-        ' gzip --decompress --stdout | dd bs=1M oflag=direct of=/dev/mmcblk0p2')
+          self.path_env +
+          ' gzip --decompress --stdout | ' +
+          'dd bs=1M oflag=direct of=/dev/mmcblk0p2')
 
       path = os.path.join(self.tempdir,
                           constants.QUICK_PROVISION_PAYLOAD_KERNEL)
@@ -318,16 +320,15 @@
 
   def test_GetRemotePartitionName(self):
     """Tests the name of the partitions."""
-    # TODO(b/190631159, b/196056723): Allow fetching once miniOS payloads exist.
     u = device_imager.MiniOSUpdater(*([None] * 5))
-    with self.assertRaises(NotImplementedError):
-      u._GetRemotePartitionName()
+    self.assertEqual(constants.QUICK_PROVISION_PAYLOAD_MINIOS,
+                     u._GetRemotePartitionName())
 
   @mock.patch.object(device_imager.MiniOSUpdater, '_CopyPartitionFromImage')
-  @mock.patch.object(device_imager.MiniOSUpdater, '_MiniOSPartitionExists',
-                     return_value=True)
+  @mock.patch.object(device_imager.MiniOSUpdater,
+                     '_MiniOSPartitionsExistInImage', return_value=True)
   @mock.patch.object(device_imager.MiniOSUpdater, '_RunPostInstall')
-  def test_Run(self, postinstall_mock, minios_mock, copy_mock):
+  def test_Run(self, postinstall_mock, partitions_exist_mock, copy_mock):
     """Test main Run() function."""
     with remote_access.ChromiumOSDeviceHandler(remote_access.TEST_IP) as device:
       device_imager.MiniOSUpdater(
@@ -335,23 +336,76 @@
           '/dev/mmcblk0p10', cros_build_lib.COMP_GZIP).Run()
 
       copy_mock.assert_called_with(constants.PART_MINIOS_A)
-      minios_mock.assert_called_with()
+      partitions_exist_mock.assert_called_with()
       postinstall_mock.assert_called_with()
 
   @mock.patch.object(device_imager.MiniOSUpdater, '_CopyPartitionFromImage')
-  @mock.patch.object(device_imager.MiniOSUpdater, '_MiniOSPartitionExists',
-                     return_value=False)
-  @mock.patch.object(device_imager.MiniOSUpdater, '_RunPostInstall')
-  def test_RunMissingMiniOS(self, postinstall_mock, minios_mock, copy_mock):
-    """Test main Run() function."""
+  @mock.patch.object(device_imager.MiniOSUpdater,
+                     '_MiniOSPartitionsExistInImage', return_value=False)
+  def test_RunMissingMiniOS(self, partitions_exist_mock, copy_mock):
+    """Test main Run() function with missing miniOS partitions on image."""
     with remote_access.ChromiumOSDeviceHandler(remote_access.TEST_IP) as device:
       device_imager.MiniOSUpdater(
           device, 'foo-image', device_imager.ImageType.FULL,
           '/dev/mmcblk0p10', cros_build_lib.COMP_GZIP).Run()
 
       copy_mock.assert_not_called()
-      minios_mock.assert_called_with()
-      postinstall_mock.assert_called_with()
+      partitions_exist_mock.assert_called_with()
+
+  @mock.patch.object(device_imager.MiniOSUpdater, '_RunPostInstall')
+  @mock.patch.object(device_imager.MiniOSUpdater, '_RedirectPartition')
+  @mock.patch.object(device_imager.MiniOSUpdater, '_MiniOSPartitionsExist')
+  @mock.patch.object(gs.GSContext, 'Exists', return_value=False)
+  def test_RunMissingMiniOSRemotePayload(self, gs_context_mock,
+                                         partitions_exist_mock, redirect_mock,
+                                         post_install_mock):
+    """Test main Run() function with missing miniOS remote payloads."""
+    with remote_access.ChromiumOSDeviceHandler(remote_access.TEST_IP) as device:
+      device_imager.MiniOSUpdater(
+          device, 'foo-image', device_imager.ImageType.REMOTE_DIRECTORY,
+          '/dev/mmcblk0p10', cros_build_lib.COMP_GZIP).Run()
+
+      post_install_mock.assert_not_called()
+      redirect_mock.assert_not_called()
+      partitions_exist_mock.assert_not_called()
+      gs_context_mock.assert_called()
+
+  @mock.patch.object(device_imager.MiniOSUpdater, '_RunPostInstall')
+  @mock.patch.object(device_imager.MiniOSUpdater, '_RedirectPartition')
+  @mock.patch.object(device_imager.MiniOSUpdater, '_MiniOSPartitionsExist',
+                     return_value=False)
+  @mock.patch.object(gs.GSContext, 'Exists', return_value=True)
+  def test_RunMissingMiniOSPartitions(self, gs_context_mock,
+                                      partitions_exist_mock, redirect_mock,
+                                      post_install_mock):
+    """Test main Run() function with missing miniOS remote payloads."""
+    with remote_access.ChromiumOSDeviceHandler(remote_access.TEST_IP) as device:
+      device_imager.MiniOSUpdater(
+          device, 'foo-image', device_imager.ImageType.REMOTE_DIRECTORY,
+          '/dev/mmcblk0p10', cros_build_lib.COMP_GZIP).Run()
+
+      post_install_mock.assert_not_called()
+      redirect_mock.assert_not_called()
+      partitions_exist_mock.assert_called()
+      gs_context_mock.assert_called()
+
+  @mock.patch.object(device_imager.MiniOSUpdater, '_RunPostInstall')
+  @mock.patch.object(device_imager.MiniOSUpdater, '_RedirectPartition')
+  @mock.patch.object(device_imager.MiniOSUpdater, '_MiniOSPartitionsExist',
+                     return_value=True)
+  @mock.patch.object(gs.GSContext, 'Exists', return_value=True)
+  def test_RunMiniOSRemotePayload(self, gs_context_mock, partitions_exist_mock,
+                                  redirect_mock, post_install_mock):
+    """Test main Run() function with missing miniOS remote payloads."""
+    with remote_access.ChromiumOSDeviceHandler(remote_access.TEST_IP) as device:
+      device_imager.MiniOSUpdater(
+          device, 'foo-image', device_imager.ImageType.REMOTE_DIRECTORY,
+          '/dev/mmcblk0p10', cros_build_lib.COMP_GZIP).Run()
+
+      post_install_mock.assert_called()
+      redirect_mock.assert_called()
+      partitions_exist_mock.assert_called()
+      gs_context_mock.assert_called()
 
   @mock.patch.object(device_imager.MiniOSUpdater, '_FlipMiniOSPriority')
   def test_RunPostInstall(self, flip_mock):
@@ -367,8 +421,8 @@
   def test_Revert(self, flip_mock):
     """Test Revert() function."""
     u = device_imager.MiniOSUpdater(
-          None, 'foo-image', device_imager.ImageType.FULL,
-          '/dev/mmcblk0p10', cros_build_lib.COMP_GZIP)
+        None, 'foo-image', device_imager.ImageType.FULL,
+        '/dev/mmcblk0p10', cros_build_lib.COMP_GZIP)
 
     # Before PostInstall runs.
     u.Revert()
@@ -385,8 +439,8 @@
   def test_FlipMiniOSPriority(self, set_mock, get_mock):
     """Test _FlipMiniOSPriority() function."""
     device_imager.MiniOSUpdater(
-          None, 'foo-image', device_imager.ImageType.FULL,
-          '/dev/mmcblk0p10', cros_build_lib.COMP_GZIP)._FlipMiniOSPriority()
+        None, 'foo-image', device_imager.ImageType.FULL,
+        '/dev/mmcblk0p10', cros_build_lib.COMP_GZIP)._FlipMiniOSPriority()
 
     get_mock.assert_called_with()
     set_mock.assert_called_with('B')
@@ -493,7 +547,8 @@
     """Test main Run() function for full image."""
     with remote_access.ChromiumOSDeviceHandler(remote_access.TEST_IP) as device:
       device_imager.StatefulUpdater(False, device, 'foo-image',
-                                 device_imager.ImageType.FULL, None, None).Run()
+                                    device_imager.ImageType.FULL, None,
+                                    None).Run()
       update_mock.assert_called_with(mock.ANY,
                                      is_payload_on_device=False,
                                      update_type=None)
@@ -505,9 +560,9 @@
     """Test main Run() function for remote images."""
     with remote_access.ChromiumOSDeviceHandler(remote_access.TEST_IP) as device:
       device_imager.StatefulUpdater(False, device, 'gs://foo-image',
-                                 device_imager.ImageType.REMOTE_DIRECTORY, None,
-                                 None).Run()
-      copy_mock.assert_called_with('gs://foo-image/stateful.tgz',mock.ANY)
+                                    device_imager.ImageType.REMOTE_DIRECTORY,
+                                    None, None).Run()
+      copy_mock.assert_called_with('gs://foo-image/stateful.tgz', mock.ANY)
       update_mock.assert_called_with(mock.ANY, is_payload_on_device=False,
                                      update_type=None)
 
diff --git a/config/chromeos_config.py b/config/chromeos_config.py
index a002bcd..98f63f3 100644
--- a/config/chromeos_config.py
+++ b/config/chromeos_config.py
@@ -343,52 +343,13 @@
   )
 
   site_config.AddTemplate(
-      'asan',
-      site_config.templates.full,
-      profile='asan',
-      # TODO(crbug.com/1080416): Investigate why rootfs verification fails and
-      # re-enable it. It used to work till late 2019.
-      rootfs_verification=False,
-      # THESE IMAGES CAN DAMAGE THE LAB and cannot be used for hardware testing.
-      disk_layout='16gb-rootfs',
-      # TODO(deymo): ASan builders generate bigger files, in particular a bigger
-      # Chrome binary, that update_engine can't handle in delta payloads due to
-      # memory limits. Remove the following lines once crbug.com/329248 is
-      # fixed.
-      images=['base', 'test'],
-      chrome_sdk=False,
-      vm_tests=[
-          config_lib.VMTestConfig(
-              constants.VM_SUITE_TEST_TYPE, test_suite='smoke')
-      ],
-      vm_tests_override=None,
-      doc='https://dev.chromium.org/chromium-os/build/builder-overview#'
-      'TOC-ASAN',
-  )
-
-  site_config.AddTemplate(
-      'ubsan',
-      profile='ubsan',
-      # Need larger rootfs for ubsan builds.
-      disk_layout='16gb-rootfs',
-      images=['base', 'test'],
-      chrome_sdk=False,
-      vm_tests=[
-          config_lib.VMTestConfig(
-              constants.VM_SUITE_TEST_TYPE, test_suite='smoke')
-      ],
-      vm_tests_override=None,
-      doc='https://dev.chromium.org/chromium-os/build/builder-overview#'
-      'TOC-ASAN',
-  )
-
-  site_config.AddTemplate(
       'fuzzer',
-      site_config.templates.full,
+      site_config.templates.internal,
       site_config.templates.informational,
       profile='fuzzer',
       chrome_sdk=False,
       sync_chrome=True,
+      usepkg_build_packages=False,
       # Run fuzzer builder specific stages.
       builder_class_name='fuzzer_builders.FuzzerBuilder',
       # Need larger rootfs since fuzzing also enables asan.
@@ -468,7 +429,7 @@
       # Because release builders never use prebuilts, they need the
       # longer timeout.  See crbug.com/938958.
       build_timeout=12 * 60 * 60,
-      useflags=config_lib.append_useflags(['-cros-debug']),
+      useflags=config_lib.append_useflags(['-cros-debug', 'thinlto']),
       manifest=constants.OFFICIAL_MANIFEST,
       manifest_version=True,
       images=['base', 'recovery', 'test', 'factory_install'],
@@ -483,20 +444,8 @@
       'chromeos-dev-installer',
       dev_installer_prebuilts=True,
       git_sync=False,
-      vm_tests=[
-          config_lib.VMTestConfig(
-              constants.VM_SUITE_TEST_TYPE, test_suite='smoke'),
-          config_lib.VMTestConfig(constants.DEV_MODE_TEST_TYPE),
-          config_lib.VMTestConfig(constants.CROS_VM_TEST_TYPE)
-      ],
-      # Some release builders disable VMTests to be able to build on GCE, but
-      # still want VMTests enabled on trybot builders.
-      vm_tests_override=[
-          config_lib.VMTestConfig(
-              constants.VM_SUITE_TEST_TYPE, test_suite='smoke'),
-          config_lib.VMTestConfig(constants.DEV_MODE_TEST_TYPE),
-          config_lib.VMTestConfig(constants.CROS_VM_TEST_TYPE)
-      ],
+      vm_tests=[],
+      vm_tests_override=[],
       paygen=True,
       signer_tests=True,
       hwqual=True,
@@ -610,39 +559,6 @@
 
   # Tast is an alternate system for running integration tests.
 
-  # The expression specified here matches the union of the tast.critical-*
-  # Autotest server tests, which are executed by the bvt-tast-cq suite on real
-  # hardware in the lab.
-  site_config.AddTemplate(
-      'tast_vm_paladin_tests',
-      tast_vm_tests=[
-          config_lib.TastVMTestConfig('tast_vm_paladin',
-                                      ['("group:mainline" && !informational)'])
-      ],
-  )
-  # The expression specified here matches the union of the
-  # tast.critical-{android,chrome} Autotest server tests, which are executed by
-  # the bvt-tast-chrome-pfq suite on real hardware in the lab.
-  site_config.AddTemplate(
-      'tast_vm_chrome_pfq_tests',
-      tast_vm_tests=[
-          config_lib.TastVMTestConfig('tast_vm_chrome_pfq', [
-              '("group:mainline" && !informational && '
-              '("dep:android*" || "dep:chrome"))'
-          ])
-      ],
-  )
-  # The expression specified here matches the tast.critical-android Autotest
-  # server test, which is executed by the bvt-tast-android-pfq suite on real
-  # hardware in the lab.
-  site_config.AddTemplate(
-      'tast_vm_android_pfq_tests',
-      tast_vm_tests=[
-          config_lib.TastVMTestConfig(
-              'tast_vm_android_pfq',
-              ['("group:mainline" && !informational && "dep:android*")'])
-      ],
-  )
   # The expression specified here matches the union of the tast.critical-* and
   # tast.informational-* Autotest server tests, which are executed by the
   # bvt-tast-cq and bvt-tast-informational suites on real hardware in the lab.
@@ -655,6 +571,15 @@
               timeout=2 * 60 * 60),
       ],
   )
+  site_config.AddTemplate(
+      'tast_vm_asan_tests',
+      tast_vm_tests=[
+          config_lib.TastVMTestConfig(
+              'tast_vm_asan_critical',
+              ['("group:asan" && !informational)'],
+              timeout=2 * 60 * 60),
+      ],
+  )
 
   site_config.AddTemplate(
       'moblab_vm_tests',
@@ -685,6 +610,42 @@
       profile='vm-optimized',
   )
 
+  site_config.AddTemplate(
+      'asan',
+      site_config.templates.full,
+      site_config.templates.tast_vm_asan_tests,
+      profile='asan',
+      # TODO(crbug.com/1080416): Investigate why rootfs verification fails and
+      # re-enable it. It used to work till late 2019.
+      rootfs_verification=False,
+      # THESE IMAGES CAN DAMAGE THE LAB and cannot be used for hardware testing.
+      disk_layout='16gb-rootfs',
+      # TODO(deymo): ASan builders generate bigger files, in particular a bigger
+      # Chrome binary, that update_engine can't handle in delta payloads due to
+      # memory limits. Remove the following lines once crbug.com/329248 is
+      # fixed.
+      images=['base', 'test'],
+      chrome_sdk=False,
+      vm_tests=[],
+      vm_tests_override=None,
+      doc='https://dev.chromium.org/chromium-os/build/builder-overview#'
+      'TOC-ASAN',
+  )
+
+  site_config.AddTemplate(
+      'ubsan',
+      profile='ubsan',
+      # Need larger rootfs for ubsan builds.
+      disk_layout='16gb-rootfs',
+      images=['base', 'test'],
+      chrome_sdk=False,
+      vm_tests=[],
+      vm_tests_override=None,
+      doc='https://dev.chromium.org/chromium-os/build/builder-overview#'
+      'TOC-ASAN',
+  )
+
+
 
 def CreateBoardConfigs(site_config, boards_dict, ge_build_config):
   """Create mixin templates for each board."""
@@ -832,20 +793,6 @@
       description='Toolchain Builds (internal)',
   )
   site_config.AddTemplate(
-      'gcc_toolchain',
-      site_config.templates.toolchain,
-      description='Full release build with next minor GCC toolchain revision',
-      useflags=config_lib.append_useflags(['next_gcc']),
-      hw_tests=hw_test_list.ToolchainTestFull(
-          constants.HWTEST_QUOTA_POOL,
-          quota_account=constants.HWTEST_QUOTA_ACCOUNT_TOOLCHAIN,
-      ),
-      hw_tests_override=hw_test_list.ToolchainTestFull(
-          constants.HWTEST_QUOTA_POOL,
-          quota_account=constants.HWTEST_QUOTA_ACCOUNT_TOOLCHAIN,
-      ),
-  )
-  site_config.AddTemplate(
       'llvm_toolchain',
       site_config.templates.toolchain,
       description='Full release build with LLVM toolchain',
@@ -873,90 +820,6 @@
       'that have been reviewed manually somehow',
   )
 
-  site_config.AddTemplate(
-      'afdo_toolchain',
-      site_config.templates.full,
-      site_config.templates.official,
-      site_config.templates.internal,
-      site_config.templates.no_vmtest_builder,
-      site_config.templates.no_hwtest_builder,
-      git_sync=False,
-      images=[],
-      unittests=False,
-      image_test=False,
-      chrome_sdk=False,
-      paygen=False,
-      signer_tests=False,
-      useflags=config_lib.append_useflags(['-cros-debug']),
-      display_label=config_lib.DISPLAY_LABEL_TOOLCHAIN,
-  )
-
-  site_config.AddTemplate(
-      'afdo_verify',
-      site_config.templates.afdo_toolchain,
-      images=['base', 'test'],
-      image_test=True,
-      unittests=True,
-  )
-  # This build config is dedicated to improve code layout of Chrome. It adopts
-  # the Call-Chain Clustering (C3) approach and other techniques to improve
-  # the code layout. It builds Chrome and generates an orderfile as a result.
-  # The orderfile will be uploaded so Chrome in the future production will use
-  # the orderfile to improve code layout.
-  #
-  # This builder is not a toolchain builder, i.e. it won't build all the
-  # toolchain. Instead, it's a release builder. It's put here because it
-  # belongs to the toolchain team.
-
-  site_config.AddTemplate(
-      'orderfile_generate_toolchain',
-      site_config.templates.afdo_toolchain,
-      orderfile_generate=True,
-      useflags=config_lib.append_useflags(
-          ['orderfile_generate', '-orderfile_use']),
-      description='Build Chrome and generate an orderfile for better layout',
-  )
-
-  site_config.AddTemplate(
-      'orderfile_verify_toolchain',
-      site_config.templates.afdo_verify,
-      orderfile_verify=True,
-      useflags=config_lib.append_useflags([
-          'orderfile_verify', '-reorder_text_sections',
-          'strict_toolchain_checks'
-      ]),
-      description='Verify the most recent orderfile is building correctly',
-  )
-
-  # This build config is used to asynchronously generate benchmark
-  # AFDO profile. It inherites from afdo_toolchain template, i.e.
-  # it is essentially a release builder but doesn't run hwtests, etc.
-  # But it should run a special HWTest "AFDOGenerate" to collect
-  # profiling data on a device. So this template needs to build image.
-  site_config.AddTemplate(
-      'benchmark_afdo_generate',
-      site_config.templates.afdo_toolchain,
-      images=['test'],
-      hw_tests=[hw_test_list.AFDORecordTest()],
-      hw_tests_override=[hw_test_list.AFDORecordTest()],
-      afdo_generate_async=True,
-      # FIXME(tcwang): Might need to revisit this later.
-      # For now, use the same useflags as PFQ AFDO generator:
-      # In other words, it turns off afdo_use, thinlto, cfi compared to
-      # release images.
-      afdo_use=False,
-      useflags=config_lib.append_useflags(
-          ['-transparent_hugepage', '-debug_fission', '-thinlto', '-cfi']),
-      description='Generate AFDO profile based on benchmarks.')
-
-  # This build config is used to verify merged and redacted AFDO profile,
-  # aka. profiles for release, can build packages without any problems.
-  site_config.AddTemplate(
-      'release_afdo_verify',
-      site_config.templates.afdo_verify,
-      description='Verify the most recent AFDO profile for release can '
-      'build Chrome images correctly.')
-
   #
   # Create toolchain tryjob builders.
   #
@@ -983,10 +846,7 @@
   site_config.Add(
       'eve-llvm-tot-toolchain',
       site_config.templates.llvm_tot_toolchain,
-      vm_tests=[
-          config_lib.VMTestConfig(
-              constants.VM_SUITE_TEST_TYPE, test_suite='smoke', use_ctest=False)
-      ],
+      vm_tests=[],
       vm_tests_override=TRADITIONAL_VM_TESTS_SUPPORTED,
       boards=['eve'],
   )
@@ -997,455 +857,6 @@
       boards=['kevin'],
   )
 
-  site_config.Add(
-      'benchmark-afdo-generate',
-      site_config.templates.benchmark_afdo_generate,
-      boards=['chell'],
-      # This builder is now running under recipes.
-      # TODO(crbug/1019868): remove this builder from legacy.
-  )
-
-  def ChromeAFDOPublishBuilders(name, board):
-    site_config.Add(
-        'chrome-' + name + '-release-afdo-verify',
-        site_config.templates.release_afdo_verify,
-        boards=[board],
-        chrome_afdo_verify=True,
-        afdo_use=False,
-        useflags=config_lib.append_useflags(['afdo_verify']),
-        # These builders are now running under recipes.
-        # TODO(crbug/1019868): remove this builder from legacy.
-        # schedule=schedule,
-    )
-
-  # Start at 7 hours after benchmark-afdo-generate, to
-  # give the builder enough time to finish.
-  # Since these builders upload different profiles, we can start
-  # them at the same time, as soon as we might get a new benchmark
-  # profile.
-  ChromeAFDOPublishBuilders('silvermont', 'chell')
-  ChromeAFDOPublishBuilders('airmont', 'snappy')
-  ChromeAFDOPublishBuilders('broadwell', 'eve')
-
-  def KernelAFDOPublishBuilders(name, board, _schedule):
-    site_config.Add(
-        name + '-release-afdo-verify',
-        site_config.templates.release_afdo_verify,
-        boards=[board],
-        kernel_afdo_verify=True,
-        # These builders are now running under recipes.
-        # TODO(crbug/1019868): remove this builder from legacy.
-        # schedule=schedule,
-    )
-
-  # Start at the same time every day. The kernel profiles are
-  # rolled every Monday, but we run these builders daily (instead of
-  # weekly), in case the Monday profile drop is red, or in case
-  # the tree is red for unrelated reasons on Monday.
-  # Schedule these tryjobs 6 hours apart from each other.
-  KernelAFDOPublishBuilders('kernel-3_18', 'chell', '0 17 * * *')
-  KernelAFDOPublishBuilders('kernel-4_4', 'eve', '0 23 * * *')
-  KernelAFDOPublishBuilders('kernel-4_14', 'octopus', '0 5 * * *')
-  KernelAFDOPublishBuilders('kernel-4_19', 'banon', '0 11 * * *')
-
-  site_config.Add(
-      'orderfile-generate-toolchain',
-      site_config.templates.orderfile_generate_toolchain,
-      # The board should not matter much, since we are not running
-      # anything on the board.
-      boards=['terra'],
-      # This builder is now running under recipes.
-      # TODO(crbug/1019868): remove this builder from legacy.
-      # schedule='0 10/12 * * *',
-  )
-
-  site_config.Add(
-      'orderfile-verify-toolchain',
-      site_config.templates.orderfile_verify_toolchain,
-      # Only test on X86 for now.
-      boards=['eve'],
-      # This builder is now running under recipes.
-      # TODO(crbug/1019868): remove this builder from legacy.
-      # schedule='0 2/12 * * *',
-  )
-
-  # This config is manually run when we want to generate a 'release' AFDO
-  # profile, which is a mixture of CWP/benchmark profiles. This is done
-  # manually once per branch, since these are (currently) hand-rolled into
-  # branches for Android and Linux builds of Chrome. See crbug.com/858856 for
-  # context (comment #4 in particular).
-  #
-  # FIXME(gbiv): Ideally, this should be done as a part of the regular AFDO
-  # pipeline if Chrome OS finds these profiles useful.
-  site_config.Add(
-      'release-afdo-profile-generate',
-      # No board is necessary; this just runs a few commands inside of the SDK.
-      boards=[],
-      build_type=constants.TOOLCHAIN_TYPE,
-      builder_class_name='release_profile_builders.ReleaseProfileMergeBuilder',
-      chrome_sdk=False,
-      description='Generates merged AFDO profiles for select Chrome releases',
-      display_label=config_lib.DISPLAY_LABEL_TOOLCHAIN,
-  )
-
-
-def AndroidTemplates(site_config):
-  """Apply Android specific config to site_config
-
-  Args:
-    site_config: config_lib.SiteConfig to be modified by adding templates
-                 and configs.
-  """
-  # Generic template shared by all Android versions.
-  site_config.AddTemplate(
-      'generic_android_pfq',
-      site_config.templates.no_vmtest_builder,
-      build_type=constants.ANDROID_PFQ_TYPE,
-      uprev=False,
-      overlays=constants.BOTH_OVERLAYS,
-      manifest_version=True,
-      sync_chrome=True,
-      android_rev=constants.ANDROID_REV_LATEST,
-      description='Preflight Android Uprev & Build (internal)',
-      luci_builder=config_lib.LUCI_BUILDER_PFQ,
-      # Raise Android PFQ timeout to 8 hours to allow for longer runs to
-      # complete successfully.
-      build_timeout=8 * 60 * 60,
-  )
-
-  # Template for Android Pi.
-  site_config.AddTemplate(
-      'pi_android_pfq',
-      site_config.templates.generic_android_pfq,
-      site_config.templates.internal,
-      display_label=config_lib.DISPLAY_LABEL_PI_ANDROID_PFQ,
-      android_package=constants.ANDROID_PI_PACKAGE,
-      android_import_branch=constants.ANDROID_PI_BUILD_BRANCH,
-  )
-
-  # Template for Android VM Rvc.
-  site_config.AddTemplate(
-      'vmrvc_android_pfq',
-      site_config.templates.generic_android_pfq,
-      site_config.templates.internal,
-      display_label=config_lib.DISPLAY_LABEL_VMRVC_ANDROID_PFQ,
-      android_package=constants.ANDROID_VMRVC_PACKAGE,
-      android_import_branch=constants.ANDROID_VMRVC_BUILD_BRANCH,
-  )
-
-  # Template for Android VM Sc.
-  site_config.AddTemplate(
-      'vmsc_android_pfq',
-      site_config.templates.generic_android_pfq,
-      site_config.templates.internal,
-      display_label=config_lib.DISPLAY_LABEL_VMSC_ANDROID_PFQ,
-      android_package=constants.ANDROID_VMSC_PACKAGE,
-      android_import_branch=constants.ANDROID_VMSC_BUILD_BRANCH,
-  )
-
-  # Template for Android T.
-  site_config.AddTemplate(
-      'vmt_android_pfq',
-      site_config.templates.generic_android_pfq,
-      site_config.templates.internal,
-      display_label=config_lib.DISPLAY_LABEL_VMT_ANDROID_PFQ,
-      android_package=constants.ANDROID_VMT_PACKAGE,
-      android_import_branch=constants.ANDROID_VMT_BUILD_BRANCH,
-  )
-
-  # Mixin for masters.
-  site_config.AddTemplate(
-      'master_android_pfq_mixin',
-      site_config.templates.internal,
-      site_config.templates.no_vmtest_builder,
-      boards=[],
-      master=True,
-      push_overlays=constants.BOTH_OVERLAYS,
-  )
-
-
-def AndroidPfqBuilders(site_config, boards_dict, ge_build_config):
-  """Create all build configs associated with the Android PFQ.
-
-  Args:
-    site_config: config_lib.SiteConfig to be modified by adding templates
-                 and configs.
-    boards_dict: A dict mapping board types to board name collections.
-    ge_build_config: Dictionary containing the decoded GE configuration file.
-  """
-  board_configs = CreateInternalBoardConfigs(site_config, boards_dict,
-                                             ge_build_config)
-  hw_test_list = HWTestList(ge_build_config)
-  # TODO(b/153392483): Temporarily remove bvt-arc from list of test
-  # suites blocking RVC PFQ.
-  vmrvc_hwtest_list = [
-      hwtest for hwtest in hw_test_list.SharedPoolPFQ()
-      if hwtest.suite != constants.HWTEST_ARC_COMMIT_SUITE
-  ]
-
-  # Android PI master.
-  pi_master_config = site_config.Add(
-      constants.PI_ANDROID_PFQ_MASTER,
-      site_config.templates.pi_android_pfq,
-      site_config.templates.master_android_pfq_mixin,
-      build_timeout=10 * 60 * 60,
-      schedule='with 60m interval',
-  )
-
-  _pi_no_hwtest_boards = _frozen_ge_set(ge_build_config, [])
-  _pi_no_hwtest_experimental_boards = _frozen_ge_set(ge_build_config, [])
-  _pi_hwtest_boards = _frozen_ge_set(
-      ge_build_config,
-      [
-          # TODO(b/172889735): Temporary disable eve because DUTs are reserved
-          # due to crbug/1141713. Instead, adding rammus to cover x86_64.
-          # 'eve',
-          'coral',
-          'grunt',
-          'kevin',
-          'rammus',
-      ])
-  _pi_hwtest_experimental_boards = _frozen_ge_set(ge_build_config, [])
-  _pi_hwtest_skylab_boards = _frozen_ge_set(
-      ge_build_config,
-      [
-          # 'eve', TODO(b/172889735): See above.
-          'coral',
-          'grunt',
-          'kevin',
-          'rammus',
-      ])
-  _pi_vmtest_boards = _frozen_ge_set(ge_build_config, [
-      'betty-pi-arc',
-  ])
-  _pi_vmtest_experimental_boards = _frozen_ge_set(ge_build_config, [])
-
-  # Android VM RVC master.
-  vmrvc_master_config = site_config.Add(
-      constants.VMRVC_ANDROID_PFQ_MASTER,
-      site_config.templates.vmrvc_android_pfq,
-      site_config.templates.master_android_pfq_mixin,
-      schedule='with 60m interval',
-  )
-
-  _vmrvc_no_hwtest_boards = _frozen_ge_set(ge_build_config, [])
-  _vmrvc_no_hwtest_experimental_boards = _frozen_ge_set(ge_build_config, [])
-  _vmrvc_hwtest_boards = _frozen_ge_set(ge_build_config, [
-      'eve-arc-r',
-      'grunt-arc-r',
-      'hatch',
-      'kukui-arc-r',
-      'rammus-arc-r',
-      'zork-arc-r',
-  ])
-  _vmrvc_hwtest_experimental_boards = _frozen_ge_set(ge_build_config, [])
-  _vmrvc_vmtest_boards = _frozen_ge_set(ge_build_config, [])
-  _vmrvc_vmtest_experimental_boards = _frozen_ge_set(ge_build_config, [])
-
-  # Android VM SC master.
-  vmsc_master_config = site_config.Add(
-      constants.VMSC_ANDROID_PFQ_MASTER,
-      site_config.templates.vmsc_android_pfq,
-      site_config.templates.master_android_pfq_mixin,
-      schedule='with 60m interval',
-  )
-
-  _vmsc_no_hwtest_boards = _frozen_ge_set(ge_build_config, [
-      'betty-arc-s',
-      'hatch-arc-s',
-  ])
-  _vmsc_no_hwtest_experimental_boards = _frozen_ge_set(ge_build_config, [])
-  _vmsc_hwtest_boards = _frozen_ge_set(ge_build_config, [])
-  _vmsc_hwtest_experimental_boards = _frozen_ge_set(ge_build_config, [])
-  _vmsc_vmtest_boards = _frozen_ge_set(ge_build_config, [])
-  _vmsc_vmtest_experimental_boards = _frozen_ge_set(ge_build_config, [])
-
-  # Android VM T master
-  vmt_master_config = site_config.Add(
-      constants.VMT_ANDROID_PFQ_MASTER,
-      site_config.templates.vmt_android_pfq,
-      site_config.templates.master_android_pfq_mixin,
-      schedule='with 150m interval')
-  _vmt_no_hwtest_boards = _frozen_ge_set(ge_build_config, [
-      'betty-arc-t',
-  ])
-  _vmt_no_hwtest_experimental_boards = _frozen_ge_set(ge_build_config, [])
-  _vmt_hwtest_boards = _frozen_ge_set(ge_build_config, [])
-  _vmt_hwtest_experimental_boards = _frozen_ge_set(ge_build_config, [])
-  _vmt_vmtest_boards = _frozen_ge_set(ge_build_config, [])
-  _vmt_vmtest_experimental_boards = _frozen_ge_set(ge_build_config, [])
-
-  # Android PI slaves.
-  pi_master_config.AddSlaves(
-      site_config.AddForBoards(
-          'pi-android-pfq',
-          _pi_hwtest_boards - _pi_hwtest_skylab_boards,
-          board_configs,
-          site_config.templates.pi_android_pfq,
-          hw_tests=hw_test_list.SharedPoolPFQ(),
-      ) + site_config.AddForBoards(
-          'pi-android-pfq',
-          _pi_hwtest_skylab_boards,
-          board_configs,
-          site_config.templates.pi_android_pfq,
-          enable_skylab_hw_tests=True,
-          hw_tests=hw_test_list.SharedPoolPFQ(),
-      ) + site_config.AddForBoards(
-          'pi-android-pfq',
-          _pi_no_hwtest_boards,
-          board_configs,
-          site_config.templates.pi_android_pfq,
-      ) + site_config.AddForBoards(
-          'pi-android-pfq',
-          _pi_no_hwtest_experimental_boards,
-          board_configs,
-          site_config.templates.pi_android_pfq,
-          important=False,
-      ) + site_config.AddForBoards(
-          'pi-android-pfq',
-          _pi_hwtest_experimental_boards,
-          board_configs,
-          site_config.templates.pi_android_pfq,
-          important=False,
-          hw_tests=hw_test_list.SharedPoolPFQ(),
-      ) + site_config.AddForBoards(
-          'pi-android-pfq',
-          _pi_vmtest_boards,
-          board_configs,
-          site_config.templates.pi_android_pfq,
-          vm_tests=[
-              config_lib.VMTestConfig(
-                  constants.VM_SUITE_TEST_TYPE, test_suite='smoke')
-          ],
-      ) + site_config.AddForBoards(
-          'pi-android-pfq',
-          _pi_vmtest_experimental_boards,
-          board_configs,
-          site_config.templates.pi_android_pfq,
-          important=False,
-          vm_tests=[
-              config_lib.VMTestConfig(
-                  constants.VM_SUITE_TEST_TYPE, test_suite='smoke')
-          ],
-      ))
-
-  # Android VMRVC slaves.
-  vmrvc_master_config.AddSlaves(
-      site_config.AddForBoards(
-          'vmrvc-android-pfq',
-          _vmrvc_hwtest_boards,
-          board_configs,
-          site_config.templates.vmrvc_android_pfq,
-          enable_skylab_hw_tests=True,
-          hw_tests=vmrvc_hwtest_list,
-      ) + site_config.AddForBoards(
-          'vmrvc-android-pfq',
-          _vmrvc_hwtest_experimental_boards,
-          board_configs,
-          site_config.templates.vmrvc_android_pfq,
-          enable_skylab_hw_tests=True,
-          hw_tests=vmrvc_hwtest_list,
-          important=False,
-      ) + site_config.AddForBoards(
-          'vmrvc-android-pfq',
-          _vmrvc_no_hwtest_boards,
-          board_configs,
-          site_config.templates.vmrvc_android_pfq,
-      ) + site_config.AddForBoards(
-          'vmrvc-android-pfq',
-          _vmrvc_no_hwtest_experimental_boards,
-          board_configs,
-          site_config.templates.vmrvc_android_pfq,
-          important=False,
-      ) + site_config.AddForBoards(
-          'vmrvc-android-pfq',
-          _vmrvc_vmtest_boards,
-          board_configs,
-          site_config.templates.vmrvc_android_pfq,
-          vm_tests=[
-              config_lib.VMTestConfig(
-                  constants.VM_SUITE_TEST_TYPE, test_suite='smoke')
-          ],
-      ))
-
-  # Android VMSC slaves.
-  vmsc_master_config.AddSlaves(
-      site_config.AddForBoards(
-          'vmsc-android-pfq',
-          _vmsc_hwtest_boards,
-          board_configs,
-          site_config.templates.vmsc_android_pfq,
-          enable_skylab_hw_tests=True,
-          hw_tests=hw_test_list.SharedPoolPFQ(),
-      ) + site_config.AddForBoards(
-          'vmsc-android-pfq',
-          _vmsc_hwtest_experimental_boards,
-          board_configs,
-          site_config.templates.vmsc_android_pfq,
-          enable_skylab_hw_tests=True,
-          hw_tests=hw_test_list.SharedPoolPFQ(),
-          important=False,
-      ) + site_config.AddForBoards(
-          'vmsc-android-pfq',
-          _vmsc_no_hwtest_boards,
-          board_configs,
-          site_config.templates.vmsc_android_pfq,
-      ) + site_config.AddForBoards(
-          'vmsc-android-pfq',
-          _vmsc_no_hwtest_experimental_boards,
-          board_configs,
-          site_config.templates.vmsc_android_pfq,
-          important=False,
-      ) + site_config.AddForBoards(
-          'vmsc-android-pfq',
-          _vmsc_vmtest_boards,
-          board_configs,
-          site_config.templates.vmsc_android_pfq,
-          vm_tests=[
-              config_lib.VMTestConfig(
-                  constants.VM_SUITE_TEST_TYPE, test_suite='smoke')
-          ],
-      ))
-
-  # Android VMT slaves.
-  vmt_master_config.AddSlaves(
-      site_config.AddForBoards(
-          'vmt-android-pfq',
-          _vmt_hwtest_boards,
-          board_configs,
-          site_config.templates.vmt_android_pfq,
-          enable_skylab_hw_tests=True,
-          hw_tests=hw_test_list.SharedPoolPFQ(),
-      ) + site_config.AddForBoards(
-          'vmt-android-pfq',
-          _vmt_hwtest_experimental_boards,
-          board_configs,
-          site_config.templates.vmt_android_pfq,
-          enable_skylab_hw_tests=True,
-          hw_tests=hw_test_list.SharedPoolPFQ(),
-          important=False,
-      ) + site_config.AddForBoards(
-          'vmt-android-pfq',
-          _vmt_no_hwtest_boards,
-          board_configs,
-          site_config.templates.vmt_android_pfq,
-      ) + site_config.AddForBoards(
-          'vmt-android-pfq',
-          _vmt_no_hwtest_experimental_boards,
-          board_configs,
-          site_config.templates.vmt_android_pfq,
-          important=False,
-      ) + site_config.AddForBoards(
-          'vmt-android-pfq',
-          _vmt_vmtest_boards,
-          board_configs,
-          site_config.templates.vmt_android_pfq,
-          vm_tests=[
-              config_lib.VMTestConfig(
-                  constants.VM_SUITE_TEST_TYPE, test_suite='smoke')
-          ],
-      ))
-
 
 def FullBuilders(site_config, boards_dict, ge_build_config):
   """Create all full builders.
@@ -1459,10 +870,13 @@
   active_builders = _frozen_ge_set(ge_build_config, [
       'eve',
       'hana',
+      'jacuzzi',
       'kevin',
       'kevin64',
+      'octopus',
       'tael',
       'tatl',
+      'zork',
   ], ('amd64-generic', 'arm-generic', 'arm64-generic'))
 
   # Move the following builders to active_builders once they are consistently
@@ -1528,83 +942,6 @@
   master_config.AddSlave(vm_config)
 
 
-def IncrementalBuilders(site_config, boards_dict, ge_build_config):
-  """Create all incremental build configs.
-
-  Args:
-    site_config: config_lib.SiteConfig to be modified by adding templates
-                 and configs.
-    boards_dict: A dict mapping board types to board name collections.
-    ge_build_config: Dictionary containing the decoded GE configuration file.
-  """
-  board_configs = CreateInternalBoardConfigs(site_config, boards_dict,
-                                             ge_build_config)
-
-  site_config.AddTemplate(
-      'incremental_affinity',
-      build_affinity=True,
-      luci_builder=config_lib.LUCI_BUILDER_INCREMENTAL,
-  )
-
-  master_config = site_config.Add(
-      'master-incremental',
-      site_config.templates.incremental,
-      site_config.templates.internal_incremental,
-      boards=[],
-      master=True,
-      manifest_version=True,
-      slave_configs=[],
-      schedule='with 10m interval',
-  )
-
-  # Build external source, for an internal board.
-  master_config.AddSlave(
-      site_config.Add(
-          'amd64-generic-incremental',
-          site_config.templates.incremental,
-          site_config.templates.incremental_affinity,
-          board_configs['amd64-generic'],
-          manifest_version=True,
-      ))
-
-  master_config.AddSlave(
-      site_config.Add(
-          'betty-incremental',
-          site_config.templates.incremental,
-          site_config.templates.internal_incremental,
-          site_config.templates.incremental_affinity,
-          boards=['betty'],
-          manifest_version=True,
-      ))
-
-  master_config.AddSlave(
-      site_config.Add(
-          'chell-incremental',
-          site_config.templates.incremental,
-          site_config.templates.internal_incremental,
-          site_config.templates.incremental_affinity,
-          boards=['chell'],
-          manifest_version=True,
-      ))
-
-  #
-  # Available, but not regularly scheduled.
-  #
-  site_config.Add(
-      'x32-generic-incremental',
-      site_config.templates.incremental,
-      board_configs['x32-generic'],
-  )
-
-  site_config.Add(
-      'beaglebone-incremental',
-      site_config.templates.incremental,
-      site_config.templates.beaglebone,
-      boards=['beaglebone'],
-      description='Incremental Beaglebone Builder',
-  )
-
-
 def InformationalBuilders(site_config, boards_dict, ge_build_config):
   """Create all informational builders.
 
@@ -1779,7 +1116,7 @@
           'setzer', 'banon', 'kefka', 'relm', 'kip'
       ]),
       (MONTHLY, 'factory-veyron-7505.B',
-       ['veyron_tiger', 'veyron_fievel', 'veyron_rialto']),
+       ['veyron_tiger', 'veyron_fievel']),
       (MONTHLY, 'factory-glados-7657.B', ['glados', 'chell']),
       (MONTHLY, 'factory-glados-7828.B',
        ['glados', 'chell', 'lars', 'sentry', 'cave', 'asuka', 'caroline']),
@@ -1813,12 +1150,15 @@
       (WEEKLY, 'factory-trogdor-13443.B', ['trogdor', 'strongbad']),
       (DAILY, 'factory-strongbad-13963.B', ['trogdor', 'strongbad']),
       (WEEKLY, 'factory-volteer-13600.B', ['volteer']),
-      (DAILY, 'factory-dedede-13683.B', ['dedede']),
+      (WEEKLY, 'factory-dedede-13683.B', ['dedede']),
       (DAILY, 'factory-keeby-14162.B', ['keeby']),
       (WEEKLY, 'factory-zork-13700.B', ['zork']),
       (WEEKLY, 'factory-puff-13813.B', ['puff']),
       (WEEKLY, 'factory-asurada-13929.B', ['asurada']),
       (WEEKLY, 'factory-ambassador-14265.B', ['ambassador']),
+      (DAILY, 'factory-kukui-14374.B', ['kukui', 'jacuzzi']),
+      (WEEKLY, 'factory-cherry-14455.B', ['cherry']),
+      (DAILY, 'factory-brya-14517.B', ['brya', 'brask']),
       # This is intended to create master branch tryjobs, NOT for production
       # builds. Update the associated list of boards as needed.
       (None, 'master', [
@@ -1839,7 +1179,8 @@
       uprev=True,
       overlays=constants.BOTH_OVERLAYS,
       push_overlays=constants.BOTH_OVERLAYS,
-      useflags=config_lib.append_useflags(['-cros-debug', 'chrome_internal']),
+      useflags=config_lib.append_useflags(['-cros-debug', 'thinlto',
+                                           'chrome_internal']),
       builder_class_name='workspace_builders.FactoryBranchBuilder',
       build_timeout=_FACTORYBRANCH_TIMEOUT,
       description='TOT builder to build a factory branch.',
@@ -2370,13 +1711,6 @@
           'hw_tests_disabled_bug': 'https://crbug.com/1092947',
       },
 
-      # No hw tests for any veyron_rialto builders. See http://b/141387161.
-      'veyron_rialto-release': {
-          'hw_tests': [],
-          'hw_tests_override': [],
-          'hw_tests_disabled_bug': 'https://b/141387161',
-      },
-
       # No hw_tests for arkham, whirlwind, gale, mistral.  See b/140317527.
       'arkham-release': {
           'hw_tests': [],
@@ -2482,19 +1816,28 @@
           'hw_tests_override': [],
           'hw_tests_disabled_bug': 'b/159934902',
       },
-      'brya-release': {
+      'draco-release': {
           'sign_types': ['recovery', 'factory'],
-          # Brya has no DUTs in the lab (b/167721012).
+          # Draco has no DUTs in the lab (b/204940128).
           'hw_tests': [],
           'hw_tests_override': [],
-          'hw_tests_disabled_bug': 'b/167721012',
+          'hw_tests_disabled_bug': 'b/204940128',
+      },
+      'brask-release': {
+          'sign_types': ['recovery', 'factory'],
+          # Brask has no DUTs in the lab (b/207095933).
+          'hw_tests': [],
+          'hw_tests_override': [],
+          'hw_tests_disabled_bug': 'b/207095933',
+      },
+      'brya-release': {
+          'sign_types': ['recovery', 'factory', 'hps_firmware'],
+      },
+      'brya-lvm-stateful-release': {
+          'sign_types': ['recovery', 'factory'],
       },
       'keeby-release': {
           'sign_types': ['recovery', 'factory'],
-          # Keeby has no DUTs in the lab. (b/185377942)
-          'hw_tests': [],
-          'hw_tests_override': [],
-          'hw_tests_disabled_bug': 'b/185377942',
       },
       'aurora-release': {
           'sign_types': ['recovery', 'factory'],
@@ -2506,6 +1849,13 @@
       'volteer-release': {
           'sign_types': ['recovery', 'factory'],
       },
+      'skolas-release': {
+          'sign_types': ['recovery', 'factory'],
+          # Skolas has no DUTs in the lab (b/209282476).
+          'hw_tests': [],
+          'hw_tests_override': [],
+          'hw_tests_disabled_bug': 'b/209282476',
+      },
 
       # See go/cros-fingerprint-firmware-branching-and-signing for details on
       # accessory_rwsig signing.
@@ -2553,6 +1903,10 @@
           'hw_tests_disabled_bug': 'https://crbug.com/1145306',
       },
 
+      'cherry-release': {
+          'sign_types': ['recovery', 'factory'],
+      },
+
       # --- end from here ---
 
       # Enable distributed ThinLTO (crbug/877722) only on nocturne for now.
@@ -2902,7 +2256,7 @@
   for board in frozenset.union(chromeos_boards.dustbuster_boards,
                                chromeos_boards.wshwos_boards):
     site_config.Add(
-        '{}-rapid'.format(board),
+        f'{board}-rapid',
         site_config.templates.release,
         site_config.templates.loonix,
         display_label=config_lib.DISPLAY_LABEL_UTILITY,
@@ -2944,20 +2298,6 @@
       unittests=False,
   )
 
-  # TODO(b/182520025): Retire once R89 PFQ is gone.
-  site_config.Add(
-      'hatch-arc-r-android-rvc-pre-flight-branch',
-      site_config.templates.pre_flight_branch,
-      display_label=config_lib.DISPLAY_LABEL_VMRVC_ANDROID_PFQ,
-      boards=['hatch-arc-r'],
-      sync_chrome=True,
-      android_rev=constants.ANDROID_REV_LATEST,
-      android_package=constants.ANDROID_VMRVC_PACKAGE,
-      android_import_branch=constants.ANDROID_VMRVC_BUILD_BRANCH,
-      prebuilts=False,
-      unittests=False,
-  )
-
   site_config.AddWithoutTemplate(
       'chromeos-infra-go',
       site_config.templates.no_hwtest_builder,
@@ -3109,7 +2449,7 @@
   # Do not remove BOT-TAG:* comments. They are used to help parse config.
   # BOT-TAG:RELEASES_START
   RELEASES = [
-      ('release-R96-14268.B',
+      ('release-R100-14526.B',
        ['kevin-android-pi-pre-flight-branch',
         'hatch-android-rvc-pre-flight-branch'],
        '',
@@ -3117,18 +2457,25 @@
        [],
        config_lib.LUCI_BUILDER_LEGACY_RELEASE),
 
-      ('release-R94-14150.B', [
-          'kevin-android-pi-pre-flight-branch',
-          'hatch-android-rvc-pre-flight-branch'
-      ], '', [], [], config_lib.LUCI_BUILDER_LEGACY_RELEASE),
-      ('release-R93-14092.B', [
-          'kevin-android-pi-pre-flight-branch',
-          'hatch-android-rvc-pre-flight-branch'
-      ], '', [], [], config_lib.LUCI_BUILDER_LEGACY_RELEASE),
+      ('release-R99-14469.B',
+       ['kevin-android-pi-pre-flight-branch',
+        'hatch-android-rvc-pre-flight-branch'],
+       '',
+       [],
+       [],
+       config_lib.LUCI_BUILDER_LEGACY_RELEASE),
+
+      ('release-R98-14388.B',
+       ['kevin-android-pi-pre-flight-branch',
+        'hatch-android-rvc-pre-flight-branch'],
+       '',
+       [],
+       [],
+       config_lib.LUCI_BUILDER_LEGACY_RELEASE),
 
       # LTS branch, please do not delete. Contact: cros-lts-team@google.com.
       # BOT-TAG:NO_PRUNE
-      ('release-R90-13816.B', [
+      ('release-R96-14268.B', [
           'kevin-android-pi-pre-flight-branch',
           'hatch-android-rvc-pre-flight-branch'
       ], 'chell-chrome-no-afdo-uprev-pre-flight-branch',
@@ -3260,18 +2607,10 @@
 
   SpecialtyBuilders(site_config, boards_dict, ge_build_config)
 
-  IncrementalBuilders(site_config, boards_dict, ge_build_config)
-
   InformationalBuilders(site_config, boards_dict, ge_build_config)
 
   FactoryBuilders(site_config, boards_dict, ge_build_config)
 
-  AndroidTemplates(site_config)
-
-  chromeos_test.AndroidTemplates(site_config)
-
-  AndroidPfqBuilders(site_config, boards_dict, ge_build_config)
-
   FullBuilders(site_config, boards_dict, ge_build_config)
 
   AddNotificationConfigs(site_config)
diff --git a/config/chromeos_config_boards.py b/config/chromeos_config_boards.py
index b264d2c..4932fd0 100644
--- a/config/chromeos_config_boards.py
+++ b/config/chromeos_config_boards.py
@@ -30,7 +30,6 @@
     'tael',
     'veyron_mighty',
     'veyron_minnie',
-    'veyron_rialto',
     'veyron_speedy',
     'viking',
     'viking-poc2',
@@ -148,4 +147,7 @@
     'zork',
     'zork-arc-r',
     'zork-borealis',
+    'skyrim',
+    'skyrim-chausie',
+    'skyrim-kernelnext',
 ])
diff --git a/config/chromeos_test_config.py b/config/chromeos_test_config.py
index 26c8707..a5f357a 100644
--- a/config/chromeos_test_config.py
+++ b/config/chromeos_test_config.py
@@ -346,9 +346,6 @@
           'vm_tests':[],
       },
 
-      'betty-pi-arc-pi-android-pfq':
-          site_config.templates.tast_vm_android_pfq_tests,
-
       # There's no amd64-generic-release builder, so we use amd64-generic-full
       # to validate informational Tast tests on amd64-generic:
       # https://crbug.com/946858
@@ -357,6 +354,7 @@
       'betty-kernelnext-release': site_config.templates.tast_vm_canary_tests,
       'betty-pi-arc-release': site_config.templates.tast_vm_canary_tests,
       'betty-release': site_config.templates.tast_vm_canary_tests,
+      'novato-release': site_config.templates.tast_vm_canary_tests,
       'reven-vmtest-release': site_config.templates.tast_vm_canary_tests,
   }
 
@@ -372,30 +370,6 @@
       logging.warning('ignoring overrides for missing config %s', config_name)
 
 
-
-def IncrementalBuilders(site_config):
-  """Create all incremental test configs.
-
-  Args:
-    site_config: config_lib.SiteConfig to be modified by adding templates
-                 and configs.
-  """
-
-  # incremental
-  site_config['amd64-generic-incremental'].apply(
-      site_config.templates.no_vmtest_builder,
-  )
-
-  site_config['betty-incremental'].apply(
-      vm_tests=getInfoVMTest(),
-      vm_tests_override=getInfoVMTest(),
-  )
-
-  site_config['x32-generic-incremental'].apply(
-      site_config.templates.no_vmtest_builder,
-  )
-
-
 def PostsubmitBuilders(site_config):
   """Create all postsubmit test configs.
 
@@ -475,16 +449,6 @@
   )
   # END asan
 
-  # BEGIN Incremental
-  site_config.templates.incremental.apply(
-      site_config.templates.default_hw_tests_override,
-  )
-
-  site_config.templates.internal_incremental.apply(
-      site_config.templates.default_hw_tests_override,
-  )
-  # END Incremental
-
   # BEGIN Factory
   site_config.templates.factory.apply(
       # site_config.templates.default_hw_tests_override,
@@ -573,22 +537,6 @@
   # END x30evb
 
 
-def AndroidTemplates(site_config):
-  """Apply test config to Android specific templates
-
-  Args:
-    site_config: config_lib.SiteConfig to be modified by adding templates
-                 and configs.
-  """
-  site_config.templates.generic_android_pfq.apply(
-      site_config.templates.default_hw_tests_override,
-  )
-
-  site_config.templates.pi_android_pfq.apply(
-      site_config.templates.default_hw_tests_override,
-  )
-
-
 def ApplyConfig(site_config, boards_dict, ge_build_config):
   """Apply test specific config to site_config
 
@@ -603,8 +551,6 @@
   for build in site_config.values():
     InsertHwTestsOverrideDefaults(build)
 
-  IncrementalBuilders(site_config)
-
   PostsubmitBuilders(site_config)
 
   EnsureVmTestsOnVmTestBoards(site_config, boards_dict, ge_build_config)
diff --git a/config/config_dump.json b/config/config_dump.json
index 660f9c6..14cbc6f 100644
--- a/config/config_dump.json
+++ b/config/config_dump.json
@@ -10,6 +10,7 @@
         "android_import_branch": null,
         "android_package": null,
         "android_rev": null,
+        "android_update_lkgb": false,
         "archive": true,
         "archive_build_debug": false,
         "base_is_recovery": false,
@@ -163,40 +164,8 @@
             "luci_builder": "Full",
             "profile": "asan",
             "rootfs_verification": false,
-            "usepkg_build_packages": false,
-            "vm_tests": [
-                "{\n    \"max_retries\": 5,\n    \"retry\": false,\n    \"test_suite\": \"smoke\",\n    \"test_type\": \"vm_suite\",\n    \"timeout\": 5400,\n    \"use_ctest\": true,\n    \"warn_only\": false\n}"
-            ]
-        },
-        "benchmark_afdo_generate": {
-            "_template": "benchmark_afdo_generate",
-            "afdo_generate_async": true,
-            "afdo_use": false,
-            "archive_build_debug": true,
-            "build_timeout": 43200,
-            "build_type": "full",
-            "chromeos_official": true,
-            "description": "Generate AFDO profile based on benchmarks.",
-            "display_label": "toolchain",
-            "doc": "https://dev.chromium.org/chromium-os/build/builder-overview#TOC-Continuous",
-            "hw_tests": [
-                "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": true,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PFQ\",\n    \"quota_account\": \"toolchain\",\n    \"retry\": true,\n    \"suite\": \"AFDO_record\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 7200,\n    \"warn_only\": false\n}"
-            ],
-            "hw_tests_override": [
-                "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": true,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PFQ\",\n    \"quota_account\": \"toolchain\",\n    \"retry\": true,\n    \"suite\": \"AFDO_record\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 7200,\n    \"warn_only\": false\n}"
-            ],
-            "internal": true,
-            "luci_builder": "Full",
-            "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
-            "overlays": "both",
-            "unittests": false,
-            "useflags": [
-                "-cfi",
-                "-cros-debug",
-                "-debug_fission",
-                "-thinlto",
-                "-transparent_hugepage",
-                "chrome_internal"
+            "tast_vm_tests": [
+                "{\n    \"suite_name\": \"tast_vm_asan_critical\",\n    \"test_exprs\": [\n        \"(\\\"group:asan\\\" && !informational)\"\n    ],\n    \"timeout\": 7200\n}"
             ],
             "usepkg_build_packages": false,
             "vm_tests": []
@@ -254,7 +223,8 @@
             "upload_hw_test_artifacts": false,
             "useflags": [
                 "-cros-debug",
-                "chrome_internal"
+                "chrome_internal",
+                "thinlto"
             ],
             "usepkg_build_packages": false,
             "vm_tests": []
@@ -290,20 +260,18 @@
         },
         "fuzzer": {
             "_template": "fuzzer",
-            "archive_build_debug": true,
-            "build_timeout": 43200,
-            "build_type": "full",
             "builder_class_name": "fuzzer_builders.FuzzerBuilder",
             "description": "Informational Builds",
             "disk_layout": "2gb-rootfs",
             "display_label": "informational",
-            "doc": "https://dev.chromium.org/chromium-os/build/builder-overview#TOC-Continuous",
-            "git_sync": true,
             "gs_path": "gs://chromeos-fuzzing-artifacts/libfuzzer-asan-buganizer",
             "hw_tests_override": [],
             "image_test": true,
             "images": [],
+            "internal": true,
             "luci_builder": "Informational",
+            "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
+            "overlays": "both",
             "packages": [
                 "virtual/target-fuzzers"
             ],
@@ -311,25 +279,6 @@
             "sync_chrome": true,
             "usepkg_build_packages": false
         },
-        "incremental": {
-            "_template": "incremental",
-            "build_type": "binary",
-            "chroot_replace": false,
-            "description": "Incremental Builds",
-            "display_label": "incremental",
-            "doc": "https://dev.chromium.org/chromium-os/build/builder-overview#TOC-Continuous",
-            "hw_tests_override": [
-                "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-                "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-                "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-                "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-                "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-                "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-                "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-            ],
-            "luci_builder": "Incremental",
-            "uprev": false
-        },
         "informational": {
             "_template": "informational",
             "description": "Informational Builds",
@@ -494,62 +443,6 @@
             "usepkg_build_packages": false,
             "vm_tests": []
         },
-        "orderfile_generate_toolchain": {
-            "_template": "orderfile_generate_toolchain",
-            "archive_build_debug": true,
-            "build_timeout": 43200,
-            "build_type": "full",
-            "chromeos_official": true,
-            "description": "Build Chrome and generate an orderfile for better layout",
-            "display_label": "toolchain",
-            "doc": "https://dev.chromium.org/chromium-os/build/builder-overview#TOC-Continuous",
-            "hw_tests_override": [],
-            "images": [],
-            "internal": true,
-            "luci_builder": "Full",
-            "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
-            "orderfile_generate": true,
-            "overlays": "both",
-            "unittests": false,
-            "useflags": [
-                "-cros-debug",
-                "-orderfile_use",
-                "chrome_internal",
-                "orderfile_generate"
-            ],
-            "usepkg_build_packages": false,
-            "vm_tests": []
-        },
-        "orderfile_verify_toolchain": {
-            "_template": "orderfile_verify_toolchain",
-            "archive_build_debug": true,
-            "build_timeout": 43200,
-            "build_type": "full",
-            "chromeos_official": true,
-            "description": "Verify the most recent orderfile is building correctly",
-            "display_label": "toolchain",
-            "doc": "https://dev.chromium.org/chromium-os/build/builder-overview#TOC-Continuous",
-            "hw_tests_override": [],
-            "image_test": true,
-            "images": [
-                "base",
-                "test"
-            ],
-            "internal": true,
-            "luci_builder": "Full",
-            "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
-            "orderfile_verify": true,
-            "overlays": "both",
-            "useflags": [
-                "-cros-debug",
-                "-reorder_text_sections",
-                "chrome_internal",
-                "orderfile_verify",
-                "strict_toolchain_checks"
-            ],
-            "usepkg_build_packages": false,
-            "vm_tests": []
-        },
         "payloads": {
             "_template": "payloads",
             "build_type": "payloads",
@@ -566,33 +459,6 @@
             "upload_hw_test_artifacts": false,
             "vm_tests": []
         },
-        "pi_android_pfq": {
-            "_template": "pi_android_pfq",
-            "android_import_branch": "git_pi-arc",
-            "android_package": "android-container-pi",
-            "android_rev": "latest_release",
-            "build_timeout": 28800,
-            "build_type": "android",
-            "description": "Preflight Android Uprev & Build (internal)",
-            "display_label": "pi_android_pfq",
-            "hw_tests_override": [
-                "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-                "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-                "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-                "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-                "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-                "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-                "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-            ],
-            "internal": true,
-            "luci_builder": "PFQ",
-            "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
-            "manifest_version": true,
-            "overlays": "both",
-            "sync_chrome": true,
-            "uprev": false,
-            "vm_tests": []
-        },
         "pre_flight_branch": {
             "_template": "pre_flight_branch",
             "branch": true,
@@ -677,45 +543,12 @@
             "upload_symbols": true,
             "useflags": [
                 "-cros-debug",
-                "chrome_internal"
+                "chrome_internal",
+                "thinlto"
             ],
             "usepkg_build_packages": false,
-            "vm_tests": [
-                "{\n    \"max_retries\": 5,\n    \"retry\": false,\n    \"test_suite\": \"smoke\",\n    \"test_type\": \"vm_suite\",\n    \"timeout\": 5400,\n    \"use_ctest\": true,\n    \"warn_only\": false\n}",
-                "{\n    \"max_retries\": 5,\n    \"retry\": false,\n    \"test_suite\": null,\n    \"test_type\": \"dev_mode_test\",\n    \"timeout\": 5400,\n    \"use_ctest\": true,\n    \"warn_only\": false\n}",
-                "{\n    \"max_retries\": 5,\n    \"retry\": false,\n    \"test_suite\": null,\n    \"test_type\": \"cros_vm_test\",\n    \"timeout\": 5400,\n    \"use_ctest\": true,\n    \"warn_only\": false\n}"
-            ],
-            "vm_tests_override": [
-                "{\n    \"max_retries\": 5,\n    \"retry\": false,\n    \"test_suite\": \"smoke\",\n    \"test_type\": \"vm_suite\",\n    \"timeout\": 5400,\n    \"use_ctest\": true,\n    \"warn_only\": false\n}",
-                "{\n    \"max_retries\": 5,\n    \"retry\": false,\n    \"test_suite\": null,\n    \"test_type\": \"dev_mode_test\",\n    \"timeout\": 5400,\n    \"use_ctest\": true,\n    \"warn_only\": false\n}",
-                "{\n    \"max_retries\": 5,\n    \"retry\": false,\n    \"test_suite\": null,\n    \"test_type\": \"cros_vm_test\",\n    \"timeout\": 5400,\n    \"use_ctest\": true,\n    \"warn_only\": false\n}"
-            ]
-        },
-        "release_afdo_verify": {
-            "_template": "release_afdo_verify",
-            "archive_build_debug": true,
-            "build_timeout": 43200,
-            "build_type": "full",
-            "chromeos_official": true,
-            "description": "Verify the most recent AFDO profile for release can build Chrome images correctly.",
-            "display_label": "toolchain",
-            "doc": "https://dev.chromium.org/chromium-os/build/builder-overview#TOC-Continuous",
-            "hw_tests_override": [],
-            "image_test": true,
-            "images": [
-                "base",
-                "test"
-            ],
-            "internal": true,
-            "luci_builder": "Full",
-            "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
-            "overlays": "both",
-            "useflags": [
-                "-cros-debug",
-                "chrome_internal"
-            ],
-            "usepkg_build_packages": false,
-            "vm_tests": []
+            "vm_tests": [],
+            "vm_tests_override": []
         },
         "release_basic": {
             "_template": "release_basic",
@@ -756,7 +589,8 @@
             "upload_stripped_packages": [],
             "useflags": [
                 "-cros-debug",
-                "chrome_internal"
+                "chrome_internal",
+                "thinlto"
             ],
             "usepkg_build_packages": false,
             "vm_tests": []
@@ -799,9 +633,7 @@
                 "test"
             ],
             "profile": "ubsan",
-            "vm_tests": [
-                "{\n    \"max_retries\": 5,\n    \"retry\": false,\n    \"test_suite\": \"smoke\",\n    \"test_type\": \"vm_suite\",\n    \"timeout\": 5400,\n    \"use_ctest\": true,\n    \"warn_only\": false\n}"
-            ]
+            "vm_tests": []
         },
         "unittest_stress": {
             "_template": "unittest_stress",
@@ -833,60 +665,6 @@
             "luci_builder": "Full",
             "profile": "vm-optimized",
             "usepkg_build_packages": false
-        },
-        "vmrvc_android_pfq": {
-            "_template": "vmrvc_android_pfq",
-            "android_import_branch": "git_rvc-arc",
-            "android_package": "android-vm-rvc",
-            "android_rev": "latest_release",
-            "build_timeout": 28800,
-            "build_type": "android",
-            "description": "Preflight Android Uprev & Build (internal)",
-            "display_label": "vmrvc_android_pfq",
-            "internal": true,
-            "luci_builder": "PFQ",
-            "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
-            "manifest_version": true,
-            "overlays": "both",
-            "sync_chrome": true,
-            "uprev": false,
-            "vm_tests": []
-        },
-        "vmsc_android_pfq": {
-            "_template": "vmsc_android_pfq",
-            "android_import_branch": "git_sc-arc-dev",
-            "android_package": "android-vm-sc",
-            "android_rev": "latest_release",
-            "build_timeout": 28800,
-            "build_type": "android",
-            "description": "Preflight Android Uprev & Build (internal)",
-            "display_label": "vmsc_android_pfq",
-            "internal": true,
-            "luci_builder": "PFQ",
-            "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
-            "manifest_version": true,
-            "overlays": "both",
-            "sync_chrome": true,
-            "uprev": false,
-            "vm_tests": []
-        },
-        "vmt_android_pfq": {
-            "_template": "vmt_android_pfq",
-            "android_import_branch": "git_master-arc-dev",
-            "android_package": "android-vm-master",
-            "android_rev": "latest_release",
-            "build_timeout": 28800,
-            "build_type": "android",
-            "description": "Preflight Android Uprev & Build (internal)",
-            "display_label": "vmt_android_pfq",
-            "internal": true,
-            "luci_builder": "PFQ",
-            "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
-            "manifest_version": true,
-            "overlays": "both",
-            "sync_chrome": true,
-            "uprev": false,
-            "vm_tests": []
         }
     },
     "adlrvp-full": {
@@ -982,9 +760,9 @@
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"adlrvp\",\n    \"name\": \"adlrvp\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"adlrvp\",\n    \"name\": \"adlrvp_extec\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"adlrvp\",\n    \"name\": \"adlrvp_m_extec\",\n    \"test_suites\": []\n}"
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"adlrvp\",\n    \"name\": \"adlrvp_m_extec\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"adlrvp\",\n    \"name\": \"adlrvp_mchp\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "adlrvp-release-tryjob": {
@@ -1008,12 +786,12 @@
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"adlrvp\",\n    \"name\": \"adlrvp\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"adlrvp\",\n    \"name\": \"adlrvp_extec\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"adlrvp\",\n    \"name\": \"adlrvp_m_extec\",\n    \"test_suites\": []\n}"
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"adlrvp\",\n    \"name\": \"adlrvp_m_extec\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"adlrvp\",\n    \"name\": \"adlrvp_mchp\",\n    \"test_suites\": []\n}"
         ],
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "adlrvp-unittest-stress": {
@@ -1147,7 +925,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"ambassador\",\n    \"name\": \"moonbuggy\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"ambassador\",\n    \"name\": \"scout\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "ambassador-release-tryjob": {
@@ -1177,7 +954,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "ambassador-unittest-stress": {
@@ -1385,38 +1161,6 @@
         ],
         "vm_tests": []
     },
-    "amd64-generic-incremental": {
-        "_template": "incremental",
-        "boards": [
-            "amd64-generic"
-        ],
-        "build_affinity": true,
-        "manifest_version": true,
-        "vm_tests": []
-    },
-    "amd64-generic-incremental-tryjob": {
-        "_template": "incremental",
-        "boards": [
-            "amd64-generic"
-        ],
-        "chroot_replace": true,
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "manifest_version": true,
-        "uprev": true,
-        "vm_tests": []
-    },
     "amd64-generic-llvm-next-toolchain": {
         "_template": "llvm_next_toolchain",
         "boards": [
@@ -1492,8 +1236,7 @@
         "hw_tests_override": [],
         "luci_builder": "Informational",
         "schedule": "0 */3 * * *",
-        "uprev": false,
-        "vm_tests": []
+        "uprev": false
     },
     "amd64-generic-ubsan-fuzzer": {
         "_template": "fuzzer",
@@ -1536,8 +1279,7 @@
         "display_label": "tryjob",
         "doc": "https://dev.chromium.org/chromium-os/build/builder-overview#TOC-Continuous",
         "hw_tests_override": null,
-        "luci_builder": "Try",
-        "vm_tests": []
+        "luci_builder": "Try"
     },
     "amd64-generic-unittest-stress": {
         "_template": "unittest_stress",
@@ -1689,7 +1431,6 @@
         "hw_tests_disabled_bug": "https://b/140317527",
         "hw_tests_override": [],
         "sync_chrome": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "arkham-release-tryjob": {
@@ -1709,7 +1450,6 @@
         "push_image": false,
         "suite_scheduling": false,
         "sync_chrome": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "arkham-unittest-stress": {
@@ -2096,7 +1836,6 @@
         ],
         "chrome_sdk_build_chrome": false,
         "enable_skylab_hw_tests": true,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "asuka-release-tryjob": {
@@ -2122,7 +1861,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "asuka-unittest-stress": {
@@ -2235,7 +1973,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"asurada\",\n    \"name\": \"hayato\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"asurada\",\n    \"name\": \"spherion\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "asurada-connectivitynext-release-tryjob": {
@@ -2264,7 +2001,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "asurada-connectivitynext-unittest-stress": {
@@ -2396,7 +2132,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"asurada\",\n    \"name\": \"hayato\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"asurada\",\n    \"name\": \"spherion\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "asurada-release-tryjob": {
@@ -2425,7 +2160,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "asurada-unittest-stress": {
@@ -2443,143 +2177,6 @@
             "chrome_internal"
         ]
     },
-    "asurada-zephyr-full": {
-        "_template": "full",
-        "boards": [
-            "asurada-zephyr"
-        ],
-        "prebuilts": "public",
-        "run_cpeexport": true,
-        "useflags": [
-            "-chrome_internal"
-        ],
-        "vm_tests": []
-    },
-    "asurada-zephyr-full-tryjob": {
-        "_template": "full",
-        "boards": [
-            "asurada-zephyr"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "prebuilts": "public",
-        "run_cpeexport": true,
-        "useflags": [
-            "-chrome_internal"
-        ],
-        "vm_tests": []
-    },
-    "asurada-zephyr-llvm-next-toolchain": {
-        "_template": "llvm_next_toolchain",
-        "boards": [
-            "asurada-zephyr"
-        ]
-    },
-    "asurada-zephyr-llvm-next-toolchain-tryjob": {
-        "_template": "llvm_next_toolchain",
-        "boards": [
-            "asurada-zephyr"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests_override": null,
-        "luci_builder": "Try"
-    },
-    "asurada-zephyr-llvm-toolchain": {
-        "_template": "llvm_toolchain",
-        "boards": [
-            "asurada-zephyr"
-        ]
-    },
-    "asurada-zephyr-llvm-toolchain-tryjob": {
-        "_template": "llvm_toolchain",
-        "boards": [
-            "asurada-zephyr"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests_override": null,
-        "luci_builder": "Try"
-    },
-    "asurada-zephyr-payloads": {
-        "_template": "payloads",
-        "boards": [
-            "asurada-zephyr"
-        ]
-    },
-    "asurada-zephyr-payloads-tryjob": {
-        "_template": "payloads",
-        "boards": [
-            "asurada-zephyr"
-        ],
-        "debug": true,
-        "hw_tests_override": null,
-        "luci_builder": "Try"
-    },
-    "asurada-zephyr-release": {
-        "_template": "release",
-        "boards": [
-            "asurada-zephyr"
-        ],
-        "models": [
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"asurada-zephyr\",\n    \"name\": \"hayato\",\n    \"test_suites\": []\n}"
-        ],
-        "vm_tests": [],
-        "vm_tests_override": null
-    },
-    "asurada-zephyr-release-tryjob": {
-        "_template": "release",
-        "boards": [
-            "asurada-zephyr"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "models": [
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"asurada-zephyr\",\n    \"name\": \"hayato\",\n    \"test_suites\": []\n}"
-        ],
-        "paygen": false,
-        "push_image": false,
-        "suite_scheduling": false,
-        "vm_tests": [],
-        "vm_tests_override": null
-    },
-    "asurada-zephyr-unittest-stress": {
-        "_template": "unittest_stress",
-        "boards": [
-            "asurada-zephyr"
-        ],
-        "hw_tests_override": null,
-        "internal": true,
-        "luci_builder": "Try",
-        "manifest": "official.xml",
-        "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
-        "overlays": "both",
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
     "atlas-blueznext-full": {
         "_template": "full",
         "boards": [
@@ -2673,7 +2270,6 @@
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"atlas-blueznext\",\n    \"name\": \"atlas\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "atlas-blueznext-release-tryjob": {
@@ -2700,7 +2296,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "atlas-blueznext-unittest-stress": {
@@ -2811,7 +2406,6 @@
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"atlas\",\n    \"name\": \"atlas\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "atlas-connectivitynext-release-tryjob": {
@@ -2838,7 +2432,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "atlas-connectivitynext-unittest-stress": {
@@ -3006,7 +2599,6 @@
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"atlas\",\n    \"name\": \"atlas\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "atlas-kernelnext-release-tryjob": {
@@ -3033,7 +2625,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "atlas-kernelnext-unittest-stress": {
@@ -3126,7 +2717,6 @@
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"atlas\",\n    \"name\": \"atlas\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "atlas-release-basic": {
@@ -3176,7 +2766,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "atlas-unittest-stress": {
@@ -3377,7 +2966,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"aurora\",\n    \"name\": \"kohaku\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"aurora\",\n    \"name\": \"nightfury\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "aurora-borealis-release-tryjob": {
@@ -3414,7 +3002,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "aurora-borealis-unittest-stress": {
@@ -3542,7 +3129,6 @@
             "recovery",
             "factory"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "aurora-release-tryjob": {
@@ -3576,7 +3162,6 @@
             "factory"
         ],
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "aurora-unittest-stress": {
@@ -3764,7 +3349,6 @@
             "banon"
         ],
         "chrome_sdk_build_chrome": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "banon-release-tryjob": {
@@ -3789,7 +3373,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "banon-unittest-stress": {
@@ -3858,43 +3441,6 @@
         ],
         "vm_tests": []
     },
-    "beaglebone-incremental": {
-        "_template": "incremental",
-        "boards": [
-            "beaglebone"
-        ],
-        "description": "Incremental Beaglebone Builder",
-        "images": [],
-        "rootfs_verification": false,
-        "sync_chrome": false,
-        "vm_tests": []
-    },
-    "beaglebone-incremental-tryjob": {
-        "_template": "incremental",
-        "boards": [
-            "beaglebone"
-        ],
-        "chroot_replace": true,
-        "debug": true,
-        "description": "Incremental Beaglebone Builder",
-        "display_label": "tryjob",
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "images": [],
-        "luci_builder": "Try",
-        "rootfs_verification": false,
-        "sync_chrome": false,
-        "uprev": true,
-        "vm_tests": []
-    },
     "beaglebone-llvm-next-toolchain": {
         "_template": "llvm_next_toolchain",
         "boards": [
@@ -3974,7 +3520,6 @@
         "rootfs_verification": false,
         "signer_tests": false,
         "sync_chrome": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "beaglebone-release-tryjob": {
@@ -4001,7 +3546,6 @@
         "signer_tests": false,
         "suite_scheduling": false,
         "sync_chrome": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "beaglebone-unittest-stress": {
@@ -4152,7 +3696,6 @@
         "rootfs_verification": false,
         "signer_tests": false,
         "sync_chrome": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "beaglebone_servo-release-tryjob": {
@@ -4179,7 +3722,6 @@
         "signer_tests": false,
         "suite_scheduling": false,
         "sync_chrome": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "beaglebone_servo-unittest-stress": {
@@ -4200,22 +3742,6 @@
             "chrome_internal"
         ]
     },
-    "benchmark-afdo-generate": {
-        "_template": "benchmark_afdo_generate",
-        "boards": [
-            "chell"
-        ]
-    },
-    "benchmark-afdo-generate-tryjob": {
-        "_template": "benchmark_afdo_generate",
-        "boards": [
-            "chell"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests_override": null,
-        "luci_builder": "Try"
-    },
     "betty-arc-r-full": {
         "_template": "full",
         "boards": [
@@ -4307,9 +3833,7 @@
         "hw_tests": [],
         "hw_tests_disabled_bug": "https://crbug.com/998427",
         "hw_tests_override": [],
-        "important": false,
-        "vm_tests": [],
-        "vm_tests_override": []
+        "important": false
     },
     "betty-arc-r-release-tryjob": {
         "_template": "release",
@@ -4326,7 +3850,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "betty-arc-r-unittest-stress": {
@@ -4435,7 +3958,6 @@
         ],
         "gce_image": true,
         "important": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "betty-arc-s-release-tryjob": {
@@ -4460,7 +3982,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "betty-arc-s-unittest-stress": {
@@ -4478,30 +3999,6 @@
             "chrome_internal"
         ]
     },
-    "betty-arc-s-vmsc-android-pfq": {
-        "_template": "vmsc_android_pfq",
-        "boards": [
-            "betty-arc-s"
-        ],
-        "manifest": "official.xml",
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
-    "betty-arc-s-vmsc-android-pfq-tryjob": {
-        "_template": "vmsc_android_pfq",
-        "boards": [
-            "betty-arc-s"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "luci_builder": "Try",
-        "manifest": "official.xml",
-        "uprev": true,
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
     "betty-arc-t-full": {
         "_template": "full",
         "boards": [
@@ -4596,7 +4093,6 @@
         "hw_tests_disabled_bug": "https://crbug.com/998427",
         "hw_tests_override": [],
         "important": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "betty-arc-t-release-tryjob": {
@@ -4614,7 +4110,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "betty-arc-t-unittest-stress": {
@@ -4632,30 +4127,6 @@
             "chrome_internal"
         ]
     },
-    "betty-arc-t-vmt-android-pfq": {
-        "_template": "vmt_android_pfq",
-        "boards": [
-            "betty-arc-t"
-        ],
-        "manifest": "official.xml",
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
-    "betty-arc-t-vmt-android-pfq-tryjob": {
-        "_template": "vmt_android_pfq",
-        "boards": [
-            "betty-arc-t"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "luci_builder": "Try",
-        "manifest": "official.xml",
-        "uprev": true,
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
     "betty-asan": {
         "_template": "asan",
         "board_replace": true,
@@ -4672,8 +4143,7 @@
         "luci_builder": "Informational",
         "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
         "overlays": "both",
-        "uprev": false,
-        "vm_tests": []
+        "uprev": false
     },
     "betty-asan-tryjob": {
         "_template": "asan",
@@ -4690,8 +4160,7 @@
         "internal": true,
         "luci_builder": "Try",
         "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
-        "overlays": "both",
-        "vm_tests": []
+        "overlays": "both"
     },
     "betty-full": {
         "_template": "full",
@@ -4728,53 +4197,6 @@
             "-chrome_internal"
         ]
     },
-    "betty-incremental": {
-        "_template": "incremental",
-        "boards": [
-            "betty"
-        ],
-        "build_affinity": true,
-        "description": "Incremental Builds (internal)",
-        "internal": true,
-        "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
-        "manifest_version": true,
-        "overlays": "both",
-        "vm_tests": [
-            "{\n    \"max_retries\": 5,\n    \"retry\": false,\n    \"test_suite\": \"vmtest-informational4\",\n    \"test_type\": \"vm_suite\",\n    \"timeout\": 43200,\n    \"use_ctest\": true,\n    \"warn_only\": true\n}"
-        ],
-        "vm_tests_override": [
-            "{\n    \"max_retries\": 5,\n    \"retry\": false,\n    \"test_suite\": \"vmtest-informational4\",\n    \"test_type\": \"vm_suite\",\n    \"timeout\": 43200,\n    \"use_ctest\": true,\n    \"warn_only\": true\n}"
-        ]
-    },
-    "betty-incremental-tryjob": {
-        "_template": "incremental",
-        "boards": [
-            "betty"
-        ],
-        "chroot_replace": true,
-        "debug": true,
-        "description": "Incremental Builds (internal)",
-        "display_label": "tryjob",
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "internal": true,
-        "luci_builder": "Try",
-        "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
-        "manifest_version": true,
-        "overlays": "both",
-        "uprev": true,
-        "vm_tests": [
-            "{\n    \"max_retries\": 5,\n    \"retry\": false,\n    \"test_suite\": \"vmtest-informational4\",\n    \"test_type\": \"vm_suite\",\n    \"timeout\": 43200,\n    \"use_ctest\": true,\n    \"warn_only\": true\n}"
-        ]
-    },
     "betty-kernelnext-full": {
         "_template": "full",
         "boards": [
@@ -5037,52 +4459,6 @@
         "hw_tests_override": null,
         "luci_builder": "Try"
     },
-    "betty-pi-arc-pi-android-pfq": {
-        "_template": "pi_android_pfq",
-        "boards": [
-            "betty-pi-arc"
-        ],
-        "manifest": "official.xml",
-        "tast_vm_tests": [
-            "{\n    \"suite_name\": \"tast_vm_android_pfq\",\n    \"test_exprs\": [\n        \"(\\\"group:mainline\\\" && !informational && \\\"dep:android*\\\")\"\n    ],\n    \"timeout\": 3600\n}"
-        ],
-        "useflags": [
-            "chrome_internal"
-        ],
-        "vm_tests": [
-            "{\n    \"max_retries\": 5,\n    \"retry\": false,\n    \"test_suite\": \"smoke\",\n    \"test_type\": \"vm_suite\",\n    \"timeout\": 5400,\n    \"use_ctest\": true,\n    \"warn_only\": false\n}"
-        ]
-    },
-    "betty-pi-arc-pi-android-pfq-tryjob": {
-        "_template": "pi_android_pfq",
-        "boards": [
-            "betty-pi-arc"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "manifest": "official.xml",
-        "tast_vm_tests": [
-            "{\n    \"suite_name\": \"tast_vm_android_pfq\",\n    \"test_exprs\": [\n        \"(\\\"group:mainline\\\" && !informational && \\\"dep:android*\\\")\"\n    ],\n    \"timeout\": 3600\n}"
-        ],
-        "uprev": true,
-        "useflags": [
-            "chrome_internal"
-        ],
-        "vm_tests": [
-            "{\n    \"max_retries\": 5,\n    \"retry\": false,\n    \"test_suite\": \"smoke\",\n    \"test_type\": \"vm_suite\",\n    \"timeout\": 5400,\n    \"use_ctest\": true,\n    \"warn_only\": false\n}"
-        ]
-    },
     "betty-pi-arc-release": {
         "_template": "release",
         "boards": [
@@ -5324,8 +4700,9 @@
         "boards": [
             "bob"
         ],
-        "chrome_sdk_build_chrome": false,
-        "vm_tests": [],
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"bob\",\n    \"name\": \"bob\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
+        ],
         "vm_tests_override": null
     },
     "bob-release-tryjob": {
@@ -5333,7 +4710,6 @@
         "boards": [
             "bob"
         ],
-        "chrome_sdk_build_chrome": false,
         "debug": true,
         "display_label": "tryjob",
         "hw_tests": [
@@ -5347,10 +4723,12 @@
         ],
         "hw_tests_override": null,
         "luci_builder": "Try",
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"bob\",\n    \"name\": \"bob\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
+        ],
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "bob-unittest-stress": {
@@ -5368,6 +4746,26 @@
             "chrome_internal"
         ]
     },
+    "brask-factory-brya-14517.B-factorybranch": {
+        "_template": "factorybranch",
+        "boards": [
+            "brask"
+        ],
+        "workspace_branch": "factory-brya-14517.B"
+    },
+    "brask-factory-brya-14517.B-factorybranch-tryjob": {
+        "_template": "factorybranch",
+        "boards": [
+            "brask"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "push_image": false,
+        "suite_scheduling": false,
+        "workspace_branch": "factory-brya-14517.B"
+    },
     "brask-full": {
         "_template": "full",
         "boards": [
@@ -5457,8 +4855,16 @@
         "boards": [
             "brask"
         ],
-        "important": false,
-        "vm_tests": [],
+        "hw_tests": [],
+        "hw_tests_disabled_bug": "b/207095933",
+        "hw_tests_override": [],
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brask\",\n    \"name\": \"brask\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
+        ],
+        "sign_types": [
+            "recovery",
+            "factory"
+        ],
         "vm_tests_override": null
     },
     "brask-release-tryjob": {
@@ -5468,21 +4874,20 @@
         ],
         "debug": true,
         "display_label": "tryjob",
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
+        "hw_tests": [],
+        "hw_tests_disabled_bug": "b/207095933",
         "hw_tests_override": null,
         "luci_builder": "Try",
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brask\",\n    \"name\": \"brask\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
+        ],
         "paygen": false,
         "push_image": false,
+        "sign_types": [
+            "recovery",
+            "factory"
+        ],
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "brask-unittest-stress": {
@@ -5500,6 +4905,26 @@
             "chrome_internal"
         ]
     },
+    "brya-factory-brya-14517.B-factorybranch": {
+        "_template": "factorybranch",
+        "boards": [
+            "brya"
+        ],
+        "workspace_branch": "factory-brya-14517.B"
+    },
+    "brya-factory-brya-14517.B-factorybranch-tryjob": {
+        "_template": "factorybranch",
+        "boards": [
+            "brya"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "push_image": false,
+        "suite_scheduling": false,
+        "workspace_branch": "factory-brya-14517.B"
+    },
     "brya-full": {
         "_template": "full",
         "boards": [
@@ -5569,6 +4994,194 @@
         "hw_tests_override": null,
         "luci_builder": "Try"
     },
+    "brya-lvm-stateful-full": {
+        "_template": "full",
+        "boards": [
+            "brya-lvm-stateful"
+        ],
+        "prebuilts": "public",
+        "run_cpeexport": true,
+        "useflags": [
+            "-chrome_internal"
+        ],
+        "vm_tests": []
+    },
+    "brya-lvm-stateful-full-tryjob": {
+        "_template": "full",
+        "boards": [
+            "brya-lvm-stateful"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests": [
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
+        ],
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "prebuilts": "public",
+        "run_cpeexport": true,
+        "useflags": [
+            "-chrome_internal"
+        ],
+        "vm_tests": []
+    },
+    "brya-lvm-stateful-llvm-next-toolchain": {
+        "_template": "llvm_next_toolchain",
+        "boards": [
+            "brya-lvm-stateful"
+        ]
+    },
+    "brya-lvm-stateful-llvm-next-toolchain-tryjob": {
+        "_template": "llvm_next_toolchain",
+        "boards": [
+            "brya-lvm-stateful"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "brya-lvm-stateful-llvm-toolchain": {
+        "_template": "llvm_toolchain",
+        "boards": [
+            "brya-lvm-stateful"
+        ]
+    },
+    "brya-lvm-stateful-llvm-toolchain-tryjob": {
+        "_template": "llvm_toolchain",
+        "boards": [
+            "brya-lvm-stateful"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "brya-lvm-stateful-payloads": {
+        "_template": "payloads",
+        "boards": [
+            "brya-lvm-stateful"
+        ]
+    },
+    "brya-lvm-stateful-payloads-tryjob": {
+        "_template": "payloads",
+        "boards": [
+            "brya-lvm-stateful"
+        ],
+        "debug": true,
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "brya-lvm-stateful-release": {
+        "_template": "release",
+        "boards": [
+            "brya-lvm-stateful"
+        ],
+        "important": false,
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"anahera\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"anahera4es\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"banshee\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"brya\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"brya4es\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"brya4esti50\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"crota\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"crota360\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"felwinter\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"gimble\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"gimble4es\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"kano\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"primus\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"primus4es\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"redrix\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"redrix4es\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"taeko\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"taeko4es\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"taniks\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"tarlo\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"vell\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"volmar\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"zavala\",\n    \"test_suites\": []\n}"
+        ],
+        "sign_types": [
+            "recovery",
+            "factory"
+        ],
+        "vm_tests_override": null
+    },
+    "brya-lvm-stateful-release-tryjob": {
+        "_template": "release",
+        "boards": [
+            "brya-lvm-stateful"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests": [
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
+        ],
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"anahera\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"anahera4es\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"banshee\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"brya\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"brya4es\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"brya4esti50\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"crota\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"crota360\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"felwinter\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"gimble\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"gimble4es\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"kano\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"primus\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"primus4es\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"redrix\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"redrix4es\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"taeko\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"taeko4es\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"taniks\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"tarlo\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"vell\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"volmar\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-lvm-stateful\",\n    \"name\": \"zavala\",\n    \"test_suites\": []\n}"
+        ],
+        "paygen": false,
+        "push_image": false,
+        "sign_types": [
+            "recovery",
+            "factory"
+        ],
+        "suite_scheduling": false,
+        "vm_tests_override": null
+    },
+    "brya-lvm-stateful-unittest-stress": {
+        "_template": "unittest_stress",
+        "boards": [
+            "brya-lvm-stateful"
+        ],
+        "hw_tests_override": null,
+        "internal": true,
+        "luci_builder": "Try",
+        "manifest": "official.xml",
+        "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
+        "overlays": "both",
+        "useflags": [
+            "chrome_internal"
+        ]
+    },
     "brya-manatee-full": {
         "_template": "full",
         "boards": [
@@ -5661,15 +5274,30 @@
         "important": false,
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"adlrvp\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"anahera\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"anahera4es\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"banshee\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"brya\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"brya4es\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"brya4esti50\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"crota\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"crota360\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"felwinter\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"gimble\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"gimble4es\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"kano\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"primus\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"primus4es\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"redrix\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"taeko\",\n    \"test_suites\": []\n}"
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"redrix4es\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"taeko\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"taeko4es\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"taniks\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"tarlo\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"vell\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"volmar\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"zavala\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "brya-manatee-release-tryjob": {
@@ -5692,18 +5320,33 @@
         "luci_builder": "Try",
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"adlrvp\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"anahera\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"anahera4es\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"banshee\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"brya\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"brya4es\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"brya4esti50\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"crota\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"crota360\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"felwinter\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"gimble\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"gimble4es\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"kano\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"primus\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"primus4es\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"redrix\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"taeko\",\n    \"test_suites\": []\n}"
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"redrix4es\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"taeko\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"taeko4es\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"taniks\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"tarlo\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"vell\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"volmar\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"zavala\",\n    \"test_suites\": []\n}"
         ],
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "brya-manatee-unittest-stress": {
@@ -5741,24 +5384,37 @@
         "boards": [
             "brya"
         ],
-        "hw_tests": [],
-        "hw_tests_disabled_bug": "b/167721012",
-        "hw_tests_override": [],
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"adlrvp\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"anahera\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"anahera4es\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"banshee\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"brya\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"brya4es\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"brya4esti50\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"crota\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"crota360\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"felwinter\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"gimble\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"kano\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"primus\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"redrix\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"taeko\",\n    \"test_suites\": []\n}"
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"gimble\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"gimble4es\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"kano\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"primus\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"primus4es\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"redrix\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"redrix4es\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"taeko\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"taeko4es\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"taniks\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"tarlo\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"vell\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"volmar\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"zavala\",\n    \"test_suites\": []\n}"
         ],
         "sign_types": [
             "recovery",
-            "factory"
+            "factory",
+            "hps_firmware"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "brya-release-tryjob": {
@@ -5768,28 +5424,51 @@
         ],
         "debug": true,
         "display_label": "tryjob",
-        "hw_tests": [],
-        "hw_tests_disabled_bug": "b/167721012",
+        "hw_tests": [
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
+        ],
         "hw_tests_override": null,
         "luci_builder": "Try",
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"adlrvp\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"anahera\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"anahera4es\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"banshee\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"brya\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"brya4es\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"brya4esti50\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"crota\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"crota360\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"felwinter\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"gimble\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"kano\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"primus\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"redrix\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"taeko\",\n    \"test_suites\": []\n}"
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"gimble\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"gimble4es\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"kano\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"primus\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"primus4es\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"redrix\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"redrix4es\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"taeko\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"taeko4es\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"taniks\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"tarlo\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"vell\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"volmar\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya\",\n    \"name\": \"zavala\",\n    \"test_suites\": []\n}"
         ],
         "paygen": false,
         "push_image": false,
         "sign_types": [
             "recovery",
-            "factory"
+            "factory",
+            "hps_firmware"
         ],
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "brya-unittest-stress": {
@@ -5807,6 +5486,144 @@
             "chrome_internal"
         ]
     },
+    "brya-zephyr-full": {
+        "_template": "full",
+        "boards": [
+            "brya-zephyr"
+        ],
+        "prebuilts": "public",
+        "run_cpeexport": true,
+        "useflags": [
+            "-chrome_internal"
+        ],
+        "vm_tests": []
+    },
+    "brya-zephyr-full-tryjob": {
+        "_template": "full",
+        "boards": [
+            "brya-zephyr"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests": [
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
+        ],
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "prebuilts": "public",
+        "run_cpeexport": true,
+        "useflags": [
+            "-chrome_internal"
+        ],
+        "vm_tests": []
+    },
+    "brya-zephyr-llvm-next-toolchain": {
+        "_template": "llvm_next_toolchain",
+        "boards": [
+            "brya-zephyr"
+        ]
+    },
+    "brya-zephyr-llvm-next-toolchain-tryjob": {
+        "_template": "llvm_next_toolchain",
+        "boards": [
+            "brya-zephyr"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "brya-zephyr-llvm-toolchain": {
+        "_template": "llvm_toolchain",
+        "boards": [
+            "brya-zephyr"
+        ]
+    },
+    "brya-zephyr-llvm-toolchain-tryjob": {
+        "_template": "llvm_toolchain",
+        "boards": [
+            "brya-zephyr"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "brya-zephyr-payloads": {
+        "_template": "payloads",
+        "boards": [
+            "brya-zephyr"
+        ]
+    },
+    "brya-zephyr-payloads-tryjob": {
+        "_template": "payloads",
+        "boards": [
+            "brya-zephyr"
+        ],
+        "debug": true,
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "brya-zephyr-release": {
+        "_template": "release",
+        "boards": [
+            "brya-zephyr"
+        ],
+        "important": false,
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-zephyr\",\n    \"name\": \"brya\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-zephyr\",\n    \"name\": \"bryati50\",\n    \"test_suites\": []\n}"
+        ],
+        "vm_tests_override": null
+    },
+    "brya-zephyr-release-tryjob": {
+        "_template": "release",
+        "boards": [
+            "brya-zephyr"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests": [
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
+        ],
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-zephyr\",\n    \"name\": \"brya\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"brya-zephyr\",\n    \"name\": \"bryati50\",\n    \"test_suites\": []\n}"
+        ],
+        "paygen": false,
+        "push_image": false,
+        "suite_scheduling": false,
+        "vm_tests_override": null
+    },
+    "brya-zephyr-unittest-stress": {
+        "_template": "unittest_stress",
+        "boards": [
+            "brya-zephyr"
+        ],
+        "hw_tests_override": null,
+        "internal": true,
+        "luci_builder": "Try",
+        "manifest": "official.xml",
+        "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
+        "overlays": "both",
+        "useflags": [
+            "chrome_internal"
+        ]
+    },
     "bubs-full": {
         "_template": "full",
         "boards": [
@@ -5896,8 +5713,6 @@
         "boards": [
             "bubs"
         ],
-        "important": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "bubs-release-tryjob": {
@@ -5921,7 +5736,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "bubs-unittest-stress": {
@@ -6150,7 +5964,6 @@
         ],
         "chrome_sdk_build_chrome": false,
         "important": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "caroline-arc64-release-tryjob": {
@@ -6175,7 +5988,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "caroline-arc64-unittest-stress": {
@@ -6270,140 +6082,6 @@
         ],
         "vm_tests": []
     },
-    "caroline-kernelnext-full": {
-        "_template": "full",
-        "boards": [
-            "caroline-kernelnext"
-        ],
-        "prebuilts": "public",
-        "run_cpeexport": true,
-        "useflags": [
-            "-chrome_internal"
-        ],
-        "vm_tests": []
-    },
-    "caroline-kernelnext-full-tryjob": {
-        "_template": "full",
-        "boards": [
-            "caroline-kernelnext"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "prebuilts": "public",
-        "run_cpeexport": true,
-        "useflags": [
-            "-chrome_internal"
-        ],
-        "vm_tests": []
-    },
-    "caroline-kernelnext-llvm-next-toolchain": {
-        "_template": "llvm_next_toolchain",
-        "boards": [
-            "caroline-kernelnext"
-        ]
-    },
-    "caroline-kernelnext-llvm-next-toolchain-tryjob": {
-        "_template": "llvm_next_toolchain",
-        "boards": [
-            "caroline-kernelnext"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests_override": null,
-        "luci_builder": "Try"
-    },
-    "caroline-kernelnext-llvm-toolchain": {
-        "_template": "llvm_toolchain",
-        "boards": [
-            "caroline-kernelnext"
-        ]
-    },
-    "caroline-kernelnext-llvm-toolchain-tryjob": {
-        "_template": "llvm_toolchain",
-        "boards": [
-            "caroline-kernelnext"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests_override": null,
-        "luci_builder": "Try"
-    },
-    "caroline-kernelnext-payloads": {
-        "_template": "payloads",
-        "boards": [
-            "caroline-kernelnext"
-        ]
-    },
-    "caroline-kernelnext-payloads-tryjob": {
-        "_template": "payloads",
-        "boards": [
-            "caroline-kernelnext"
-        ],
-        "debug": true,
-        "hw_tests_override": null,
-        "luci_builder": "Try"
-    },
-    "caroline-kernelnext-release": {
-        "_template": "release",
-        "boards": [
-            "caroline-kernelnext"
-        ],
-        "chrome_sdk_build_chrome": false,
-        "important": false,
-        "vm_tests": [],
-        "vm_tests_override": null
-    },
-    "caroline-kernelnext-release-tryjob": {
-        "_template": "release",
-        "boards": [
-            "caroline-kernelnext"
-        ],
-        "chrome_sdk_build_chrome": false,
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "paygen": false,
-        "push_image": false,
-        "suite_scheduling": false,
-        "vm_tests": [],
-        "vm_tests_override": null
-    },
-    "caroline-kernelnext-unittest-stress": {
-        "_template": "unittest_stress",
-        "boards": [
-            "caroline-kernelnext"
-        ],
-        "hw_tests_override": null,
-        "internal": true,
-        "luci_builder": "Try",
-        "manifest": "official.xml",
-        "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
-        "overlays": "both",
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
     "caroline-llvm-next-toolchain": {
         "_template": "llvm_next_toolchain",
         "boards": [
@@ -6530,7 +6208,6 @@
         "hw_tests_disabled_bug": "http://crbug.com/1091053",
         "hw_tests_override": [],
         "important": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "caroline-ndktranslation-release-tryjob": {
@@ -6548,7 +6225,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "caroline-ndktranslation-unittest-stress": {
@@ -6587,7 +6263,6 @@
             "caroline"
         ],
         "chrome_sdk_build_chrome": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "caroline-release-tryjob": {
@@ -6612,7 +6287,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "caroline-unittest-stress": {
@@ -6721,7 +6395,6 @@
         ],
         "chrome_sdk_build_chrome": false,
         "important": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "caroline-userdebug-release-tryjob": {
@@ -6746,7 +6419,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "caroline-userdebug-unittest-stress": {
@@ -6893,8 +6565,9 @@
         "boards": [
             "cave"
         ],
-        "chrome_sdk_build_chrome": false,
-        "vm_tests": [],
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"cave\",\n    \"name\": \"cave\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
+        ],
         "vm_tests_override": null
     },
     "cave-release-tryjob": {
@@ -6902,7 +6575,6 @@
         "boards": [
             "cave"
         ],
-        "chrome_sdk_build_chrome": false,
         "debug": true,
         "display_label": "tryjob",
         "hw_tests": [
@@ -6916,10 +6588,12 @@
         ],
         "hw_tests_override": null,
         "luci_builder": "Try",
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"cave\",\n    \"name\": \"cave\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
+        ],
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "cave-unittest-stress": {
@@ -7067,7 +6741,6 @@
             "celes"
         ],
         "chrome_sdk_build_chrome": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "celes-release-tryjob": {
@@ -7092,7 +6765,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "celes-unittest-stress": {
@@ -7255,46 +6927,6 @@
         ],
         "vm_tests": []
     },
-    "chell-incremental": {
-        "_template": "incremental",
-        "boards": [
-            "chell"
-        ],
-        "build_affinity": true,
-        "description": "Incremental Builds (internal)",
-        "internal": true,
-        "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
-        "manifest_version": true,
-        "overlays": "both",
-        "vm_tests": []
-    },
-    "chell-incremental-tryjob": {
-        "_template": "incremental",
-        "boards": [
-            "chell"
-        ],
-        "chroot_replace": true,
-        "debug": true,
-        "description": "Incremental Builds (internal)",
-        "display_label": "tryjob",
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "internal": true,
-        "luci_builder": "Try",
-        "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
-        "manifest_version": true,
-        "overlays": "both",
-        "uprev": true,
-        "vm_tests": []
-    },
     "chell-llvm-next-toolchain": {
         "_template": "llvm_next_toolchain",
         "boards": [
@@ -7347,7 +6979,6 @@
         "boards": [
             "chell"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "chell-release-tryjob": {
@@ -7371,7 +7002,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "chell-unittest-stress": {
@@ -7389,6 +7019,26 @@
             "chrome_internal"
         ]
     },
+    "cherry-factory-cherry-14455.B-factorybranch": {
+        "_template": "factorybranch",
+        "boards": [
+            "cherry"
+        ],
+        "workspace_branch": "factory-cherry-14455.B"
+    },
+    "cherry-factory-cherry-14455.B-factorybranch-tryjob": {
+        "_template": "factorybranch",
+        "boards": [
+            "cherry"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "push_image": false,
+        "suite_scheduling": false,
+        "workspace_branch": "factory-cherry-14455.B"
+    },
     "cherry-full": {
         "_template": "full",
         "boards": [
@@ -7480,9 +7130,12 @@
         ],
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"cherry\",\n    \"name\": \"cherry\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"cherry\",\n    \"name\": \"tomato\",\n    \"test_suites\": []\n}"
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"cherry\",\n    \"name\": \"tomato\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
-        "vm_tests": [],
+        "sign_types": [
+            "recovery",
+            "factory"
+        ],
         "vm_tests_override": null
     },
     "cherry-release-tryjob": {
@@ -7505,12 +7158,15 @@
         "luci_builder": "Try",
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"cherry\",\n    \"name\": \"cherry\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"cherry\",\n    \"name\": \"tomato\",\n    \"test_suites\": []\n}"
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"cherry\",\n    \"name\": \"tomato\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
         "paygen": false,
         "push_image": false,
+        "sign_types": [
+            "recovery",
+            "factory"
+        ],
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "cherry-unittest-stress": {
@@ -7528,93 +7184,141 @@
             "chrome_internal"
         ]
     },
-    "chrome-airmont-release-afdo-verify": {
-        "_template": "release_afdo_verify",
-        "afdo_use": false,
+    "cherry64-full": {
+        "_template": "full",
         "boards": [
-            "snappy"
+            "cherry64"
         ],
-        "chrome_afdo_verify": true,
+        "prebuilts": "public",
+        "run_cpeexport": true,
         "useflags": [
-            "-cros-debug",
-            "afdo_verify",
-            "chrome_internal"
+            "-chrome_internal"
+        ],
+        "vm_tests": []
+    },
+    "cherry64-full-tryjob": {
+        "_template": "full",
+        "boards": [
+            "cherry64"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests": [
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
+        ],
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "prebuilts": "public",
+        "run_cpeexport": true,
+        "useflags": [
+            "-chrome_internal"
+        ],
+        "vm_tests": []
+    },
+    "cherry64-llvm-next-toolchain": {
+        "_template": "llvm_next_toolchain",
+        "boards": [
+            "cherry64"
         ]
     },
-    "chrome-airmont-release-afdo-verify-tryjob": {
-        "_template": "release_afdo_verify",
-        "afdo_use": false,
+    "cherry64-llvm-next-toolchain-tryjob": {
+        "_template": "llvm_next_toolchain",
         "boards": [
-            "snappy"
+            "cherry64"
         ],
-        "chrome_afdo_verify": true,
         "debug": true,
         "display_label": "tryjob",
         "hw_tests_override": null,
-        "luci_builder": "Try",
-        "useflags": [
-            "-cros-debug",
-            "afdo_verify",
-            "chrome_internal"
+        "luci_builder": "Try"
+    },
+    "cherry64-llvm-toolchain": {
+        "_template": "llvm_toolchain",
+        "boards": [
+            "cherry64"
         ]
     },
-    "chrome-broadwell-release-afdo-verify": {
-        "_template": "release_afdo_verify",
-        "afdo_use": false,
+    "cherry64-llvm-toolchain-tryjob": {
+        "_template": "llvm_toolchain",
         "boards": [
-            "eve"
+            "cherry64"
         ],
-        "chrome_afdo_verify": true,
-        "useflags": [
-            "-cros-debug",
-            "afdo_verify",
-            "chrome_internal"
-        ]
-    },
-    "chrome-broadwell-release-afdo-verify-tryjob": {
-        "_template": "release_afdo_verify",
-        "afdo_use": false,
-        "boards": [
-            "eve"
-        ],
-        "chrome_afdo_verify": true,
         "debug": true,
         "display_label": "tryjob",
         "hw_tests_override": null,
-        "luci_builder": "Try",
-        "useflags": [
-            "-cros-debug",
-            "afdo_verify",
-            "chrome_internal"
+        "luci_builder": "Try"
+    },
+    "cherry64-payloads": {
+        "_template": "payloads",
+        "boards": [
+            "cherry64"
         ]
     },
-    "chrome-silvermont-release-afdo-verify": {
-        "_template": "release_afdo_verify",
-        "afdo_use": false,
+    "cherry64-payloads-tryjob": {
+        "_template": "payloads",
         "boards": [
-            "chell"
+            "cherry64"
         ],
-        "chrome_afdo_verify": true,
-        "useflags": [
-            "-cros-debug",
-            "afdo_verify",
-            "chrome_internal"
-        ]
+        "debug": true,
+        "hw_tests_override": null,
+        "luci_builder": "Try"
     },
-    "chrome-silvermont-release-afdo-verify-tryjob": {
-        "_template": "release_afdo_verify",
-        "afdo_use": false,
+    "cherry64-release": {
+        "_template": "release",
         "boards": [
-            "chell"
+            "cherry64"
         ],
-        "chrome_afdo_verify": true,
+        "important": false,
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"cherry64\",\n    \"name\": \"cherry\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"cherry64\",\n    \"name\": \"tomato\",\n    \"test_suites\": []\n}"
+        ],
+        "vm_tests_override": null
+    },
+    "cherry64-release-tryjob": {
+        "_template": "release",
+        "boards": [
+            "cherry64"
+        ],
         "debug": true,
         "display_label": "tryjob",
+        "hw_tests": [
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
+        ],
         "hw_tests_override": null,
         "luci_builder": "Try",
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"cherry64\",\n    \"name\": \"cherry\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"cherry64\",\n    \"name\": \"tomato\",\n    \"test_suites\": []\n}"
+        ],
+        "paygen": false,
+        "push_image": false,
+        "suite_scheduling": false,
+        "vm_tests_override": null
+    },
+    "cherry64-unittest-stress": {
+        "_template": "unittest_stress",
+        "boards": [
+            "cherry64"
+        ],
+        "hw_tests_override": null,
+        "internal": true,
+        "luci_builder": "Try",
+        "manifest": "official.xml",
+        "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
+        "overlays": "both",
         "useflags": [
-            "-cros-debug",
-            "afdo_verify",
             "chrome_internal"
         ]
     },
@@ -7958,7 +7662,26 @@
             "coral-kernelnext"
         ],
         "important": false,
-        "vm_tests": [],
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"astronaut\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"babymega\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"babytiger\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"blacktip\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"blacktip360\",\n    \"test_suites\": [\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"blacktiplte\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"blue\",\n    \"test_suites\": [\n        \"au\"\n    ]\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"bruce\",\n    \"test_suites\": [\n        \"bvt-inline\",\n        \"bvt-tast-cq\"\n    ]\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"epaulette\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"lava\",\n    \"test_suites\": [\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"nasher\",\n    \"test_suites\": [\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"nasher360\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"porbeagle\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"rabbid\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"robo\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"robo360\",\n    \"test_suites\": [\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"santa\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"whitetip\",\n    \"test_suites\": [\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
+        ],
         "vm_tests_override": null
     },
     "coral-kernelnext-release-tryjob": {
@@ -7979,10 +7702,29 @@
         ],
         "hw_tests_override": null,
         "luci_builder": "Try",
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"astronaut\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"babymega\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"babytiger\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"blacktip\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"blacktip360\",\n    \"test_suites\": [\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"blacktiplte\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"blue\",\n    \"test_suites\": [\n        \"au\"\n    ]\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"bruce\",\n    \"test_suites\": [\n        \"bvt-inline\",\n        \"bvt-tast-cq\"\n    ]\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"epaulette\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"lava\",\n    \"test_suites\": [\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"nasher\",\n    \"test_suites\": [\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"nasher360\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"porbeagle\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"rabbid\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"robo\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"robo360\",\n    \"test_suites\": [\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"santa\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"whitetip\",\n    \"test_suites\": [\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
+        ],
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "coral-kernelnext-unittest-stress": {
@@ -8067,47 +7809,6 @@
         "hw_tests_override": null,
         "luci_builder": "Try"
     },
-    "coral-pi-android-pfq": {
-        "_template": "pi_android_pfq",
-        "boards": [
-            "coral"
-        ],
-        "enable_skylab_hw_tests": true,
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": true,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": true,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"pfq\",\n    \"retry\": true,\n    \"suite\": \"sanity\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": true,\n    \"max_retries\": 5,\n    \"minimum_duts\": 3,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PFQ\",\n    \"quota_account\": \"pfq\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 3,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": true,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PFQ\",\n    \"quota_account\": \"pfq\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-android-pfq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}"
-        ],
-        "manifest": "official.xml",
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
-    "coral-pi-android-pfq-tryjob": {
-        "_template": "pi_android_pfq",
-        "boards": [
-            "coral"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "enable_skylab_hw_tests": true,
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "manifest": "official.xml",
-        "uprev": true,
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
     "coral-release": {
         "_template": "release",
         "boards": [
@@ -8133,7 +7834,6 @@
             "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"santa\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": false,\n    \"lab_board_name\": \"coral\",\n    \"name\": \"whitetip\",\n    \"test_suites\": [\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "coral-release-tryjob": {
@@ -8177,7 +7877,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "coral-unittest-stress": {
@@ -8195,6 +7894,135 @@
             "chrome_internal"
         ]
     },
+    "corsola-full": {
+        "_template": "full",
+        "boards": [
+            "corsola"
+        ],
+        "prebuilts": "public",
+        "run_cpeexport": true,
+        "useflags": [
+            "-chrome_internal"
+        ],
+        "vm_tests": []
+    },
+    "corsola-full-tryjob": {
+        "_template": "full",
+        "boards": [
+            "corsola"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests": [
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
+        ],
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "prebuilts": "public",
+        "run_cpeexport": true,
+        "useflags": [
+            "-chrome_internal"
+        ],
+        "vm_tests": []
+    },
+    "corsola-llvm-next-toolchain": {
+        "_template": "llvm_next_toolchain",
+        "boards": [
+            "corsola"
+        ]
+    },
+    "corsola-llvm-next-toolchain-tryjob": {
+        "_template": "llvm_next_toolchain",
+        "boards": [
+            "corsola"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "corsola-llvm-toolchain": {
+        "_template": "llvm_toolchain",
+        "boards": [
+            "corsola"
+        ]
+    },
+    "corsola-llvm-toolchain-tryjob": {
+        "_template": "llvm_toolchain",
+        "boards": [
+            "corsola"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "corsola-payloads": {
+        "_template": "payloads",
+        "boards": [
+            "corsola"
+        ]
+    },
+    "corsola-payloads-tryjob": {
+        "_template": "payloads",
+        "boards": [
+            "corsola"
+        ],
+        "debug": true,
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "corsola-release": {
+        "_template": "release",
+        "boards": [
+            "corsola"
+        ],
+        "vm_tests_override": null
+    },
+    "corsola-release-tryjob": {
+        "_template": "release",
+        "boards": [
+            "corsola"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests": [
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
+        ],
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "paygen": false,
+        "push_image": false,
+        "suite_scheduling": false,
+        "vm_tests_override": null
+    },
+    "corsola-unittest-stress": {
+        "_template": "unittest_stress",
+        "boards": [
+            "corsola"
+        ],
+        "hw_tests_override": null,
+        "internal": true,
+        "luci_builder": "Try",
+        "manifest": "official.xml",
+        "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
+        "overlays": "both",
+        "useflags": [
+            "chrome_internal"
+        ]
+    },
     "cyan-factory-strago-7458.B-factorybranch": {
         "_template": "factorybranch",
         "boards": [
@@ -8324,7 +8152,6 @@
         "boards": [
             "cyan"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "cyan-release-tryjob": {
@@ -8348,7 +8175,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "cyan-unittest-stress": {
@@ -8476,10 +8302,12 @@
             "dedede"
         ],
         "models": [
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"beetley\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"beetley\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"blipper\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"bookem\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"boten\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"botenflex\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"bugzzy\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"cret\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"cret360\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"drawcia\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
@@ -8487,22 +8315,25 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"drawman\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"drawper\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"galith\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"galith360\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"gallop\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"galnat\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"galtic\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"galnat\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"galtic\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"galtic360\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"kracko\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"kracko360\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"lantis\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"madoo\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"magister\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"maglet\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"maglet\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"maglia\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"maglith\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"magma\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"magneto\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"magneto\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"magolor\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"magpie\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"metaknight\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"pasara\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"pirette\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"pirika\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"sasuke\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
@@ -8519,7 +8350,6 @@
             "recovery",
             "factory"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "dedede-release-tryjob": {
@@ -8541,10 +8371,12 @@
         "hw_tests_override": null,
         "luci_builder": "Try",
         "models": [
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"beetley\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"beetley\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"blipper\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"bookem\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"boten\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"botenflex\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"bugzzy\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"cret\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"cret360\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"drawcia\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
@@ -8552,22 +8384,25 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"drawman\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"drawper\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"galith\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"galith360\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"gallop\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"galnat\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"galtic\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"galnat\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"galtic\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"galtic360\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"kracko\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"kracko360\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"lantis\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"madoo\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"magister\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"maglet\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"maglet\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"maglia\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"maglith\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"magma\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"magneto\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"magneto\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"magolor\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"magpie\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"metaknight\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"pasara\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"pirette\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"pirika\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"dedede\",\n    \"name\": \"sasuke\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
@@ -8584,7 +8419,6 @@
             "factory"
         ],
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "dedede-unittest-stress": {
@@ -8691,7 +8525,6 @@
         "boards": [
             "deltaur"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "deltaur-release-tryjob": {
@@ -8715,7 +8548,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "deltaur-unittest-stress": {
@@ -8733,6 +8565,148 @@
             "chrome_internal"
         ]
     },
+    "draco-full": {
+        "_template": "full",
+        "boards": [
+            "draco"
+        ],
+        "prebuilts": "public",
+        "run_cpeexport": true,
+        "useflags": [
+            "-chrome_internal"
+        ],
+        "vm_tests": []
+    },
+    "draco-full-tryjob": {
+        "_template": "full",
+        "boards": [
+            "draco"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests": [
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
+        ],
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "prebuilts": "public",
+        "run_cpeexport": true,
+        "useflags": [
+            "-chrome_internal"
+        ],
+        "vm_tests": []
+    },
+    "draco-llvm-next-toolchain": {
+        "_template": "llvm_next_toolchain",
+        "boards": [
+            "draco"
+        ]
+    },
+    "draco-llvm-next-toolchain-tryjob": {
+        "_template": "llvm_next_toolchain",
+        "boards": [
+            "draco"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "draco-llvm-toolchain": {
+        "_template": "llvm_toolchain",
+        "boards": [
+            "draco"
+        ]
+    },
+    "draco-llvm-toolchain-tryjob": {
+        "_template": "llvm_toolchain",
+        "boards": [
+            "draco"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "draco-payloads": {
+        "_template": "payloads",
+        "boards": [
+            "draco"
+        ]
+    },
+    "draco-payloads-tryjob": {
+        "_template": "payloads",
+        "boards": [
+            "draco"
+        ],
+        "debug": true,
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "draco-release": {
+        "_template": "release",
+        "boards": [
+            "draco"
+        ],
+        "hw_tests": [],
+        "hw_tests_disabled_bug": "b/204940128",
+        "hw_tests_override": [],
+        "important": false,
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"draco\",\n    \"name\": \"agah\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"draco\",\n    \"name\": \"draco\",\n    \"test_suites\": []\n}"
+        ],
+        "sign_types": [
+            "recovery",
+            "factory"
+        ],
+        "vm_tests_override": null
+    },
+    "draco-release-tryjob": {
+        "_template": "release",
+        "boards": [
+            "draco"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests": [],
+        "hw_tests_disabled_bug": "b/204940128",
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"draco\",\n    \"name\": \"agah\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"draco\",\n    \"name\": \"draco\",\n    \"test_suites\": []\n}"
+        ],
+        "paygen": false,
+        "push_image": false,
+        "sign_types": [
+            "recovery",
+            "factory"
+        ],
+        "suite_scheduling": false,
+        "vm_tests_override": null
+    },
+    "draco-unittest-stress": {
+        "_template": "unittest_stress",
+        "boards": [
+            "draco"
+        ],
+        "hw_tests_override": null,
+        "internal": true,
+        "luci_builder": "Try",
+        "manifest": "official.xml",
+        "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
+        "overlays": "both",
+        "useflags": [
+            "chrome_internal"
+        ]
+    },
     "drallion-factory-drallion-13080.B-factorybranch": {
         "_template": "factorybranch",
         "boards": [
@@ -8872,7 +8846,6 @@
             "recovery",
             "factory"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "drallion-release-tryjob": {
@@ -8906,7 +8879,6 @@
             "factory"
         ],
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "drallion-unittest-stress": {
@@ -9054,7 +9026,6 @@
             "edgar"
         ],
         "chrome_sdk_build_chrome": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "edgar-release-tryjob": {
@@ -9079,7 +9050,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "edgar-unittest-stress": {
@@ -9190,7 +9160,6 @@
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"elm\",\n    \"name\": \"elm\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "elm-arc64-release-tryjob": {
@@ -9217,7 +9186,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "elm-arc64-unittest-stress": {
@@ -9328,7 +9296,6 @@
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"elm\",\n    \"name\": \"elm\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "elm-connectivitynext-release-tryjob": {
@@ -9355,7 +9322,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "elm-connectivitynext-unittest-stress": {
@@ -9523,7 +9489,6 @@
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"elm\",\n    \"name\": \"elm\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "elm-kernelnext-release-tryjob": {
@@ -9550,7 +9515,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "elm-kernelnext-unittest-stress": {
@@ -9623,7 +9587,6 @@
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"elm\",\n    \"name\": \"elm\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "elm-release-tryjob": {
@@ -9650,7 +9613,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "elm-unittest-stress": {
@@ -9781,7 +9743,6 @@
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"endeavour\",\n    \"name\": \"endeavour\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "endeavour-release-tryjob": {
@@ -9808,7 +9769,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "endeavour-unittest-stress": {
@@ -10002,7 +9962,6 @@
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"eve\",\n    \"name\": \"eve\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "eve-arc-r-release-tryjob": {
@@ -10022,7 +9981,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "eve-arc-r-unittest-stress": {
@@ -10040,44 +9998,6 @@
             "chrome_internal"
         ]
     },
-    "eve-arc-r-vmrvc-android-pfq": {
-        "_template": "vmrvc_android_pfq",
-        "boards": [
-            "eve-arc-r"
-        ],
-        "enable_skylab_hw_tests": true,
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": true,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": true,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"pfq\",\n    \"retry\": true,\n    \"suite\": \"sanity\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": true,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PFQ\",\n    \"quota_account\": \"pfq\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-android-pfq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": [
-            "{\n    \"async\": false,\n    \"blocking\": true,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"DEFAULT\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"sanity\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"DEFAULT\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-android-pfq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}"
-        ],
-        "manifest": "official.xml",
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
-    "eve-arc-r-vmrvc-android-pfq-tryjob": {
-        "_template": "vmrvc_android_pfq",
-        "boards": [
-            "eve-arc-r"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "enable_skylab_hw_tests": true,
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": true,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"DEFAULT\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"sanity\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"DEFAULT\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-android-pfq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}"
-        ],
-        "luci_builder": "Try",
-        "manifest": "official.xml",
-        "uprev": true,
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
     "eve-arm64-full": {
         "_template": "full",
         "boards": [
@@ -10171,7 +10091,6 @@
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"eve-arm64\",\n    \"name\": \"eve\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "eve-arm64-release-tryjob": {
@@ -10198,7 +10117,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "eve-arm64-unittest-stress": {
@@ -10275,144 +10193,6 @@
         ],
         "vm_tests": []
     },
-    "eve-kernelnext-full": {
-        "_template": "full",
-        "boards": [
-            "eve-kernelnext"
-        ],
-        "prebuilts": "public",
-        "run_cpeexport": true,
-        "useflags": [
-            "-chrome_internal"
-        ],
-        "vm_tests": []
-    },
-    "eve-kernelnext-full-tryjob": {
-        "_template": "full",
-        "boards": [
-            "eve-kernelnext"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "prebuilts": "public",
-        "run_cpeexport": true,
-        "useflags": [
-            "-chrome_internal"
-        ],
-        "vm_tests": []
-    },
-    "eve-kernelnext-llvm-next-toolchain": {
-        "_template": "llvm_next_toolchain",
-        "boards": [
-            "eve-kernelnext"
-        ]
-    },
-    "eve-kernelnext-llvm-next-toolchain-tryjob": {
-        "_template": "llvm_next_toolchain",
-        "boards": [
-            "eve-kernelnext"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests_override": null,
-        "luci_builder": "Try"
-    },
-    "eve-kernelnext-llvm-toolchain": {
-        "_template": "llvm_toolchain",
-        "boards": [
-            "eve-kernelnext"
-        ]
-    },
-    "eve-kernelnext-llvm-toolchain-tryjob": {
-        "_template": "llvm_toolchain",
-        "boards": [
-            "eve-kernelnext"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests_override": null,
-        "luci_builder": "Try"
-    },
-    "eve-kernelnext-payloads": {
-        "_template": "payloads",
-        "boards": [
-            "eve-kernelnext"
-        ]
-    },
-    "eve-kernelnext-payloads-tryjob": {
-        "_template": "payloads",
-        "boards": [
-            "eve-kernelnext"
-        ],
-        "debug": true,
-        "hw_tests_override": null,
-        "luci_builder": "Try"
-    },
-    "eve-kernelnext-release": {
-        "_template": "release",
-        "boards": [
-            "eve-kernelnext"
-        ],
-        "important": false,
-        "models": [
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"eve\",\n    \"name\": \"eve\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
-        ],
-        "vm_tests": [],
-        "vm_tests_override": null
-    },
-    "eve-kernelnext-release-tryjob": {
-        "_template": "release",
-        "boards": [
-            "eve-kernelnext"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "models": [
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"eve\",\n    \"name\": \"eve\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
-        ],
-        "paygen": false,
-        "push_image": false,
-        "suite_scheduling": false,
-        "vm_tests": [],
-        "vm_tests_override": null
-    },
-    "eve-kernelnext-unittest-stress": {
-        "_template": "unittest_stress",
-        "boards": [
-            "eve-kernelnext"
-        ],
-        "hw_tests_override": null,
-        "internal": true,
-        "luci_builder": "Try",
-        "manifest": "official.xml",
-        "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
-        "overlays": "both",
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
     "eve-kvm-full": {
         "_template": "full",
         "boards": [
@@ -10509,7 +10289,6 @@
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"eve\",\n    \"name\": \"eve\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "eve-kvm-release-tryjob": {
@@ -10529,7 +10308,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "eve-kvm-unittest-stress": {
@@ -10638,7 +10416,6 @@
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"eve\",\n    \"name\": \"eve\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "eve-release-basic": {
@@ -10688,7 +10465,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "eve-unittest-stress": {
@@ -10802,7 +10578,6 @@
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"eve\",\n    \"name\": \"eve\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "eve-userdebug-release-tryjob": {
@@ -10822,7 +10597,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "eve-userdebug-unittest-stress": {
@@ -10953,7 +10727,6 @@
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"excelsior\",\n    \"name\": \"excelsior\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "excelsior-release-tryjob": {
@@ -10980,7 +10753,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "excelsior-unittest-stress": {
@@ -11162,6 +10934,52 @@
         ],
         "workspace_branch": "factory-auron-6772.B"
     },
+    "factory-brya-14517.B-buildspec": {
+        "_template": "buildspec",
+        "build_timeout": 43200,
+        "display_label": "factory",
+        "schedule": "with 24h interval",
+        "slave_configs": [
+            "brask-factory-brya-14517.B-factorybranch",
+            "brya-factory-brya-14517.B-factorybranch"
+        ],
+        "workspace_branch": "factory-brya-14517.B"
+    },
+    "factory-brya-14517.B-buildspec-tryjob": {
+        "_template": "buildspec",
+        "build_timeout": 43200,
+        "debug": true,
+        "debug_cidb": true,
+        "display_label": "tryjob",
+        "luci_builder": "Try",
+        "slave_configs": [
+            "brask-factory-brya-14517.B-factorybranch-tryjob",
+            "brya-factory-brya-14517.B-factorybranch-tryjob"
+        ],
+        "workspace_branch": "factory-brya-14517.B"
+    },
+    "factory-cherry-14455.B-buildspec": {
+        "_template": "buildspec",
+        "build_timeout": 43200,
+        "display_label": "factory",
+        "schedule": "with 168h interval",
+        "slave_configs": [
+            "cherry-factory-cherry-14455.B-factorybranch"
+        ],
+        "workspace_branch": "factory-cherry-14455.B"
+    },
+    "factory-cherry-14455.B-buildspec-tryjob": {
+        "_template": "buildspec",
+        "build_timeout": 43200,
+        "debug": true,
+        "debug_cidb": true,
+        "display_label": "tryjob",
+        "luci_builder": "Try",
+        "slave_configs": [
+            "cherry-factory-cherry-14455.B-factorybranch-tryjob"
+        ],
+        "workspace_branch": "factory-cherry-14455.B"
+    },
     "factory-coral-10122.B-buildspec": {
         "_template": "buildspec",
         "build_timeout": 43200,
@@ -11188,7 +11006,7 @@
         "_template": "buildspec",
         "build_timeout": 43200,
         "display_label": "factory",
-        "schedule": "with 24h interval",
+        "schedule": "with 168h interval",
         "slave_configs": [
             "dedede-factory-dedede-13683.B-factorybranch"
         ],
@@ -11556,6 +11374,30 @@
         ],
         "workspace_branch": "factory-kukui-12587.B"
     },
+    "factory-kukui-14374.B-buildspec": {
+        "_template": "buildspec",
+        "build_timeout": 43200,
+        "display_label": "factory",
+        "schedule": "with 24h interval",
+        "slave_configs": [
+            "jacuzzi-factory-kukui-14374.B-factorybranch",
+            "kukui-factory-kukui-14374.B-factorybranch"
+        ],
+        "workspace_branch": "factory-kukui-14374.B"
+    },
+    "factory-kukui-14374.B-buildspec-tryjob": {
+        "_template": "buildspec",
+        "build_timeout": 43200,
+        "debug": true,
+        "debug_cidb": true,
+        "display_label": "tryjob",
+        "luci_builder": "Try",
+        "slave_configs": [
+            "jacuzzi-factory-kukui-14374.B-factorybranch-tryjob",
+            "kukui-factory-kukui-14374.B-factorybranch-tryjob"
+        ],
+        "workspace_branch": "factory-kukui-14374.B"
+    },
     "factory-mistral-12361.B-buildspec": {
         "_template": "buildspec",
         "build_timeout": 43200,
@@ -12017,7 +11859,6 @@
         "schedule": "with 720h interval",
         "slave_configs": [
             "veyron_fievel-factory-veyron-7505.B-factorybranch",
-            "veyron_rialto-factory-veyron-7505.B-factorybranch",
             "veyron_tiger-factory-veyron-7505.B-factorybranch"
         ],
         "workspace_branch": "factory-veyron-7505.B"
@@ -12031,7 +11872,6 @@
         "luci_builder": "Try",
         "slave_configs": [
             "veyron_fievel-factory-veyron-7505.B-factorybranch-tryjob",
-            "veyron_rialto-factory-veyron-7505.B-factorybranch-tryjob",
             "veyron_tiger-factory-veyron-7505.B-factorybranch-tryjob"
         ],
         "workspace_branch": "factory-veyron-7505.B"
@@ -12199,7 +12039,6 @@
         "boards": [
             "falco_li"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "falco_li-release-tryjob": {
@@ -12223,7 +12062,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "falco_li-unittest-stress": {
@@ -12357,7 +12195,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"fizz\",\n    \"name\": \"teemo\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"fizz\",\n    \"name\": \"wukong\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "fizz-cfm-release-tryjob": {
@@ -12388,7 +12225,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "fizz-cfm-unittest-stress": {
@@ -12463,6 +12299,150 @@
         ],
         "vm_tests": []
     },
+    "fizz-kernelnext-full": {
+        "_template": "full",
+        "boards": [
+            "fizz-kernelnext"
+        ],
+        "prebuilts": "public",
+        "run_cpeexport": true,
+        "useflags": [
+            "-chrome_internal"
+        ],
+        "vm_tests": []
+    },
+    "fizz-kernelnext-full-tryjob": {
+        "_template": "full",
+        "boards": [
+            "fizz-kernelnext"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests": [
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
+        ],
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "prebuilts": "public",
+        "run_cpeexport": true,
+        "useflags": [
+            "-chrome_internal"
+        ],
+        "vm_tests": []
+    },
+    "fizz-kernelnext-llvm-next-toolchain": {
+        "_template": "llvm_next_toolchain",
+        "boards": [
+            "fizz-kernelnext"
+        ]
+    },
+    "fizz-kernelnext-llvm-next-toolchain-tryjob": {
+        "_template": "llvm_next_toolchain",
+        "boards": [
+            "fizz-kernelnext"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "fizz-kernelnext-llvm-toolchain": {
+        "_template": "llvm_toolchain",
+        "boards": [
+            "fizz-kernelnext"
+        ]
+    },
+    "fizz-kernelnext-llvm-toolchain-tryjob": {
+        "_template": "llvm_toolchain",
+        "boards": [
+            "fizz-kernelnext"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "fizz-kernelnext-payloads": {
+        "_template": "payloads",
+        "boards": [
+            "fizz-kernelnext"
+        ]
+    },
+    "fizz-kernelnext-payloads-tryjob": {
+        "_template": "payloads",
+        "boards": [
+            "fizz-kernelnext"
+        ],
+        "debug": true,
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "fizz-kernelnext-release": {
+        "_template": "release",
+        "boards": [
+            "fizz-kernelnext"
+        ],
+        "important": false,
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"fizz\",\n    \"name\": \"jax\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"fizz\",\n    \"name\": \"kench\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"fizz\",\n    \"name\": \"sion\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"fizz\",\n    \"name\": \"teemo\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"fizz\",\n    \"name\": \"wukong\",\n    \"test_suites\": []\n}"
+        ],
+        "vm_tests_override": null
+    },
+    "fizz-kernelnext-release-tryjob": {
+        "_template": "release",
+        "boards": [
+            "fizz-kernelnext"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests": [
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
+        ],
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"fizz\",\n    \"name\": \"jax\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"fizz\",\n    \"name\": \"kench\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"fizz\",\n    \"name\": \"sion\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"fizz\",\n    \"name\": \"teemo\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"fizz\",\n    \"name\": \"wukong\",\n    \"test_suites\": []\n}"
+        ],
+        "paygen": false,
+        "push_image": false,
+        "suite_scheduling": false,
+        "vm_tests_override": null
+    },
+    "fizz-kernelnext-unittest-stress": {
+        "_template": "unittest_stress",
+        "boards": [
+            "fizz-kernelnext"
+        ],
+        "hw_tests_override": null,
+        "internal": true,
+        "luci_builder": "Try",
+        "manifest": "official.xml",
+        "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
+        "overlays": "both",
+        "useflags": [
+            "chrome_internal"
+        ]
+    },
     "fizz-labstation-full": {
         "_template": "full",
         "boards": [
@@ -12565,7 +12545,6 @@
         ],
         "paygen": false,
         "signer_tests": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "fizz-labstation-release-tryjob": {
@@ -12599,7 +12578,6 @@
         "push_image": false,
         "signer_tests": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "fizz-labstation-unittest-stress": {
@@ -12780,7 +12758,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"fizz-moblab\",\n    \"name\": \"wukong\",\n    \"test_suites\": [\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"au\",\n        \"bvt-cq\"\n    ]\n}"
         ],
         "signer_tests": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "fizz-moblab-release-tryjob": {
@@ -12808,7 +12785,6 @@
         "push_image": false,
         "signer_tests": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "fizz-moblab-unittest-stress": {
@@ -12853,7 +12829,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"fizz\",\n    \"name\": \"teemo\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"fizz\",\n    \"name\": \"wukong\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "fizz-release-tryjob": {
@@ -12884,7 +12859,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "fizz-unittest-stress": {
@@ -13047,7 +13021,6 @@
         "hw_tests_override": [],
         "paygen_skip_testing": true,
         "sync_chrome": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "gale-release-tryjob": {
@@ -13067,7 +13040,6 @@
         "push_image": false,
         "suite_scheduling": false,
         "sync_chrome": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "gale-test-ap": {
@@ -13320,7 +13292,6 @@
         "boards": [
             "glados"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "glados-release-tryjob": {
@@ -13344,7 +13315,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "glados-unittest-stress": {
@@ -13493,7 +13463,6 @@
         ],
         "chrome_sdk_build_chrome": false,
         "important": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "goroh-release-tryjob": {
@@ -13518,7 +13487,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "goroh-unittest-stress": {
@@ -13666,7 +13634,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"grunt\",\n    \"name\": \"treeya360\",\n    \"test_suites\": []\n}"
         ],
         "unittests": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "grunt-arc-r-release-tryjob": {
@@ -13704,7 +13671,6 @@
         "push_image": false,
         "suite_scheduling": false,
         "unittests": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "grunt-arc-r-unittest-stress": {
@@ -13722,46 +13688,6 @@
             "chrome_internal"
         ]
     },
-    "grunt-arc-r-vmrvc-android-pfq": {
-        "_template": "vmrvc_android_pfq",
-        "boards": [
-            "grunt-arc-r"
-        ],
-        "enable_skylab_hw_tests": true,
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": true,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": true,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"pfq\",\n    \"retry\": true,\n    \"suite\": \"sanity\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": true,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PFQ\",\n    \"quota_account\": \"pfq\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-android-pfq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": [
-            "{\n    \"async\": false,\n    \"blocking\": true,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"DEFAULT\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"sanity\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"DEFAULT\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-android-pfq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}"
-        ],
-        "manifest": "official.xml",
-        "unittests": false,
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
-    "grunt-arc-r-vmrvc-android-pfq-tryjob": {
-        "_template": "vmrvc_android_pfq",
-        "boards": [
-            "grunt-arc-r"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "enable_skylab_hw_tests": true,
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": true,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"DEFAULT\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"sanity\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"DEFAULT\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-android-pfq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}"
-        ],
-        "luci_builder": "Try",
-        "manifest": "official.xml",
-        "unittests": false,
-        "uprev": true,
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
     "grunt-factory-grunt-11164.135.B-factorybranch": {
         "_template": "factorybranch",
         "boards": [
@@ -13945,7 +13871,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"grunt\",\n    \"name\": \"treeya360\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
         "unittests": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "grunt-kernelnext-release-tryjob": {
@@ -13983,7 +13908,6 @@
         "push_image": false,
         "suite_scheduling": false,
         "unittests": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "grunt-kernelnext-unittest-stress": {
@@ -14052,49 +13976,6 @@
         "hw_tests_override": null,
         "luci_builder": "Try"
     },
-    "grunt-pi-android-pfq": {
-        "_template": "pi_android_pfq",
-        "boards": [
-            "grunt"
-        ],
-        "enable_skylab_hw_tests": true,
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": true,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": true,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"pfq\",\n    \"retry\": true,\n    \"suite\": \"sanity\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": true,\n    \"max_retries\": 5,\n    \"minimum_duts\": 3,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PFQ\",\n    \"quota_account\": \"pfq\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 3,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": true,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PFQ\",\n    \"quota_account\": \"pfq\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-android-pfq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}"
-        ],
-        "manifest": "official.xml",
-        "unittests": false,
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
-    "grunt-pi-android-pfq-tryjob": {
-        "_template": "pi_android_pfq",
-        "boards": [
-            "grunt"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "enable_skylab_hw_tests": true,
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "manifest": "official.xml",
-        "unittests": false,
-        "uprev": true,
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
     "grunt-release": {
         "_template": "release",
         "boards": [
@@ -14115,7 +13996,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"grunt\",\n    \"name\": \"treeya360\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
         "unittests": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "grunt-release-basic": {
@@ -14199,7 +14079,6 @@
         "push_image": false,
         "suite_scheduling": false,
         "unittests": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "grunt-unittest-stress": {
@@ -14354,7 +14233,6 @@
         ],
         "image_test": false,
         "important": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "guado-macrophage-release-tryjob": {
@@ -14379,7 +14257,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "guado-macrophage-unittest-stress": {
@@ -14496,7 +14373,6 @@
         "important": false,
         "paygen": false,
         "signer_tests": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "guado_labstation-release-tryjob": {
@@ -14527,7 +14403,6 @@
         "push_image": false,
         "signer_tests": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "guado_labstation-unittest-stress": {
@@ -14641,16 +14516,16 @@
             "guybrush"
         ],
         "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"guybrush\",\n    \"name\": \"dewatt\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"guybrush\",\n    \"name\": \"guybrush\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"guybrush\",\n    \"name\": \"guybrush360\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"guybrush\",\n    \"name\": \"nipperkin\",\n    \"test_suites\": []\n}"
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"guybrush\",\n    \"name\": \"nipperkin\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
         "sign_types": [
             "recovery",
             "factory"
         ],
         "unittests": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "guybrush-release-tryjob": {
@@ -14672,9 +14547,10 @@
         "hw_tests_override": null,
         "luci_builder": "Try",
         "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"guybrush\",\n    \"name\": \"dewatt\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"guybrush\",\n    \"name\": \"guybrush\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"guybrush\",\n    \"name\": \"guybrush360\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"guybrush\",\n    \"name\": \"nipperkin\",\n    \"test_suites\": []\n}"
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"guybrush\",\n    \"name\": \"nipperkin\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
         "paygen": false,
         "push_image": false,
@@ -14684,7 +14560,6 @@
         ],
         "suite_scheduling": false,
         "unittests": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "guybrush-unittest-stress": {
@@ -14792,7 +14667,6 @@
             "hana-arc64"
         ],
         "important": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "hana-arc64-release-tryjob": {
@@ -14816,7 +14690,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "hana-arc64-unittest-stress": {
@@ -14983,7 +14856,6 @@
             "hana-kernelnext"
         ],
         "important": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "hana-kernelnext-release-tryjob": {
@@ -15007,7 +14879,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "hana-kernelnext-unittest-stress": {
@@ -15078,7 +14949,6 @@
             "hana"
         ],
         "chrome_sdk_build_chrome": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "hana-release-tryjob": {
@@ -15103,7 +14973,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "hana-unittest-stress": {
@@ -15252,7 +15121,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-arc-r-ack\",\n    \"name\": \"kohaku\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-arc-r-ack\",\n    \"name\": \"nightfury\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "hatch-arc-r-ack-release-tryjob": {
@@ -15289,7 +15157,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "hatch-arc-r-ack-unittest-stress": {
@@ -15307,34 +15174,6 @@
             "chrome_internal"
         ]
     },
-    "hatch-arc-r-android-rvc-pre-flight-branch": {
-        "_template": "pre_flight_branch",
-        "android_import_branch": "git_rvc-arc",
-        "android_package": "android-vm-rvc",
-        "android_rev": "latest_release",
-        "boards": [
-            "hatch-arc-r"
-        ],
-        "display_label": "vmrvc_android_pfq",
-        "sync_chrome": true,
-        "vm_tests_override": null
-    },
-    "hatch-arc-r-android-rvc-pre-flight-branch-tryjob": {
-        "_template": "pre_flight_branch",
-        "android_import_branch": "git_rvc-arc",
-        "android_package": "android-vm-rvc",
-        "android_rev": "latest_release",
-        "boards": [
-            "hatch-arc-r"
-        ],
-        "debug": true,
-        "debug_cidb": true,
-        "display_label": "tryjob",
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "sync_chrome": true,
-        "vm_tests_override": null
-    },
     "hatch-arc-r-full": {
         "_template": "full",
         "boards": [
@@ -15438,7 +15277,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"kohaku\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"nightfury\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "hatch-arc-r-release-tryjob": {
@@ -15475,7 +15313,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "hatch-arc-r-unittest-stress": {
@@ -15596,7 +15433,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"kohaku\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"nightfury\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "hatch-arc-r-userdebug-release-tryjob": {
@@ -15633,7 +15469,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "hatch-arc-r-userdebug-unittest-stress": {
@@ -15754,7 +15589,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"kohaku\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"nightfury\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "hatch-arc-s-release-tryjob": {
@@ -15791,7 +15625,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "hatch-arc-s-unittest-stress": {
@@ -15809,26 +15642,162 @@
             "chrome_internal"
         ]
     },
-    "hatch-arc-s-vmsc-android-pfq": {
-        "_template": "vmsc_android_pfq",
+    "hatch-arc-t-full": {
+        "_template": "full",
         "boards": [
-            "hatch-arc-s"
+            "hatch-arc-t"
         ],
-        "manifest": "official.xml",
+        "prebuilts": "public",
+        "run_cpeexport": true,
         "useflags": [
-            "chrome_internal"
-        ]
+            "-chrome_internal"
+        ],
+        "vm_tests": []
     },
-    "hatch-arc-s-vmsc-android-pfq-tryjob": {
-        "_template": "vmsc_android_pfq",
+    "hatch-arc-t-full-tryjob": {
+        "_template": "full",
         "boards": [
-            "hatch-arc-s"
+            "hatch-arc-t"
         ],
         "debug": true,
         "display_label": "tryjob",
+        "hw_tests": [
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
+        ],
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "prebuilts": "public",
+        "run_cpeexport": true,
+        "useflags": [
+            "-chrome_internal"
+        ],
+        "vm_tests": []
+    },
+    "hatch-arc-t-llvm-next-toolchain": {
+        "_template": "llvm_next_toolchain",
+        "boards": [
+            "hatch-arc-t"
+        ]
+    },
+    "hatch-arc-t-llvm-next-toolchain-tryjob": {
+        "_template": "llvm_next_toolchain",
+        "boards": [
+            "hatch-arc-t"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "hatch-arc-t-llvm-toolchain": {
+        "_template": "llvm_toolchain",
+        "boards": [
+            "hatch-arc-t"
+        ]
+    },
+    "hatch-arc-t-llvm-toolchain-tryjob": {
+        "_template": "llvm_toolchain",
+        "boards": [
+            "hatch-arc-t"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "hatch-arc-t-payloads": {
+        "_template": "payloads",
+        "boards": [
+            "hatch-arc-t"
+        ]
+    },
+    "hatch-arc-t-payloads-tryjob": {
+        "_template": "payloads",
+        "boards": [
+            "hatch-arc-t"
+        ],
+        "debug": true,
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "hatch-arc-t-release": {
+        "_template": "release",
+        "boards": [
+            "hatch-arc-t"
+        ],
+        "important": false,
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-arc-t\",\n    \"name\": \"akemi\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-arc-t\",\n    \"name\": \"dragonair\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-arc-t\",\n    \"name\": \"dratini\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-arc-t\",\n    \"name\": \"hatch\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-arc-t\",\n    \"name\": \"helios\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-arc-t\",\n    \"name\": \"helios_diskswap\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-arc-t\",\n    \"name\": \"jinlon\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-arc-t\",\n    \"name\": \"kindred\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-arc-t\",\n    \"name\": \"kled\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-arc-t\",\n    \"name\": \"kohaku\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-arc-t\",\n    \"name\": \"nightfury\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-arc-t\",\n    \"name\": \"unprovisioned_dratini\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-arc-t\",\n    \"name\": \"unprovisioned_jinlon\",\n    \"test_suites\": []\n}"
+        ],
+        "vm_tests_override": null
+    },
+    "hatch-arc-t-release-tryjob": {
+        "_template": "release",
+        "boards": [
+            "hatch-arc-t"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests": [
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
+        ],
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-arc-t\",\n    \"name\": \"akemi\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-arc-t\",\n    \"name\": \"dragonair\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-arc-t\",\n    \"name\": \"dratini\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-arc-t\",\n    \"name\": \"hatch\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-arc-t\",\n    \"name\": \"helios\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-arc-t\",\n    \"name\": \"helios_diskswap\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-arc-t\",\n    \"name\": \"jinlon\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-arc-t\",\n    \"name\": \"kindred\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-arc-t\",\n    \"name\": \"kled\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-arc-t\",\n    \"name\": \"kohaku\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-arc-t\",\n    \"name\": \"nightfury\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-arc-t\",\n    \"name\": \"unprovisioned_dratini\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-arc-t\",\n    \"name\": \"unprovisioned_jinlon\",\n    \"test_suites\": []\n}"
+        ],
+        "paygen": false,
+        "push_image": false,
+        "suite_scheduling": false,
+        "vm_tests_override": null
+    },
+    "hatch-arc-t-unittest-stress": {
+        "_template": "unittest_stress",
+        "boards": [
+            "hatch-arc-t"
+        ],
+        "hw_tests_override": null,
+        "internal": true,
         "luci_builder": "Try",
         "manifest": "official.xml",
-        "uprev": true,
+        "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
+        "overlays": "both",
         "useflags": [
             "chrome_internal"
         ]
@@ -15936,7 +15905,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-blueznext\",\n    \"name\": \"kohaku\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-blueznext\",\n    \"name\": \"nightfury\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "hatch-blueznext-release-tryjob": {
@@ -15973,7 +15941,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "hatch-blueznext-unittest-stress": {
@@ -16107,7 +16074,6 @@
         "notification_configs": [
             "{\n    \"email\": \"borealis-release-builder-alerts@google.com\",\n    \"template\": \"legacy_release\",\n    \"threshold\": 2\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "hatch-borealis-release-tryjob": {
@@ -16145,7 +16111,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "hatch-borealis-unittest-stress": {
@@ -16268,7 +16233,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"unprovisioned_dratini\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"unprovisioned_jinlon\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "hatch-connectivitynext-release-tryjob": {
@@ -16307,7 +16271,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "hatch-connectivitynext-unittest-stress": {
@@ -16429,7 +16392,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-diskswap\",\n    \"name\": \"kohaku\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch-diskswap\",\n    \"name\": \"nightfury\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "hatch-diskswap-release-tryjob": {
@@ -16467,7 +16429,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "hatch-diskswap-unittest-stress": {
@@ -16645,7 +16606,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"kohaku\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"nightfury\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "hatch-kernelnext-release-tryjob": {
@@ -16682,7 +16642,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "hatch-kernelnext-unittest-stress": {
@@ -16732,164 +16691,6 @@
         "hw_tests_override": null,
         "luci_builder": "Try"
     },
-    "hatch-manatee-full": {
-        "_template": "full",
-        "boards": [
-            "hatch-manatee"
-        ],
-        "prebuilts": "public",
-        "run_cpeexport": true,
-        "useflags": [
-            "-chrome_internal"
-        ],
-        "vm_tests": []
-    },
-    "hatch-manatee-full-tryjob": {
-        "_template": "full",
-        "boards": [
-            "hatch-manatee"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "prebuilts": "public",
-        "run_cpeexport": true,
-        "useflags": [
-            "-chrome_internal"
-        ],
-        "vm_tests": []
-    },
-    "hatch-manatee-llvm-next-toolchain": {
-        "_template": "llvm_next_toolchain",
-        "boards": [
-            "hatch-manatee"
-        ]
-    },
-    "hatch-manatee-llvm-next-toolchain-tryjob": {
-        "_template": "llvm_next_toolchain",
-        "boards": [
-            "hatch-manatee"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests_override": null,
-        "luci_builder": "Try"
-    },
-    "hatch-manatee-llvm-toolchain": {
-        "_template": "llvm_toolchain",
-        "boards": [
-            "hatch-manatee"
-        ]
-    },
-    "hatch-manatee-llvm-toolchain-tryjob": {
-        "_template": "llvm_toolchain",
-        "boards": [
-            "hatch-manatee"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests_override": null,
-        "luci_builder": "Try"
-    },
-    "hatch-manatee-payloads": {
-        "_template": "payloads",
-        "boards": [
-            "hatch-manatee"
-        ]
-    },
-    "hatch-manatee-payloads-tryjob": {
-        "_template": "payloads",
-        "boards": [
-            "hatch-manatee"
-        ],
-        "debug": true,
-        "hw_tests_override": null,
-        "luci_builder": "Try"
-    },
-    "hatch-manatee-release": {
-        "_template": "release",
-        "boards": [
-            "hatch-manatee"
-        ],
-        "important": false,
-        "models": [
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"akemi\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"dragonair\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"dratini\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"hatch\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"helios\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"helios_diskswap\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"jinlon\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"kindred\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"kled\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"kohaku\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"nightfury\",\n    \"test_suites\": []\n}"
-        ],
-        "vm_tests": [],
-        "vm_tests_override": null
-    },
-    "hatch-manatee-release-tryjob": {
-        "_template": "release",
-        "boards": [
-            "hatch-manatee"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "models": [
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"akemi\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"dragonair\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"dratini\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"hatch\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"helios\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"helios_diskswap\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"jinlon\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"kindred\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"kled\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"kohaku\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"hatch\",\n    \"name\": \"nightfury\",\n    \"test_suites\": []\n}"
-        ],
-        "paygen": false,
-        "push_image": false,
-        "suite_scheduling": false,
-        "vm_tests": [],
-        "vm_tests_override": null
-    },
-    "hatch-manatee-unittest-stress": {
-        "_template": "unittest_stress",
-        "boards": [
-            "hatch-manatee"
-        ],
-        "hw_tests_override": null,
-        "internal": true,
-        "luci_builder": "Try",
-        "manifest": "official.xml",
-        "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
-        "overlays": "both",
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
     "hatch-payloads": {
         "_template": "payloads",
         "boards": [
@@ -16928,7 +16729,6 @@
             "factory",
             "accessory_rwsig"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "hatch-release-tryjob": {
@@ -16970,7 +16770,6 @@
             "accessory_rwsig"
         ],
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "hatch-unittest-stress": {
@@ -16988,44 +16787,6 @@
             "chrome_internal"
         ]
     },
-    "hatch-vmrvc-android-pfq": {
-        "_template": "vmrvc_android_pfq",
-        "boards": [
-            "hatch"
-        ],
-        "enable_skylab_hw_tests": true,
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": true,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": true,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"pfq\",\n    \"retry\": true,\n    \"suite\": \"sanity\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": true,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PFQ\",\n    \"quota_account\": \"pfq\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-android-pfq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": [
-            "{\n    \"async\": false,\n    \"blocking\": true,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"DEFAULT\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"sanity\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"DEFAULT\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-android-pfq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}"
-        ],
-        "manifest": "official.xml",
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
-    "hatch-vmrvc-android-pfq-tryjob": {
-        "_template": "vmrvc_android_pfq",
-        "boards": [
-            "hatch"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "enable_skylab_hw_tests": true,
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": true,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"DEFAULT\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"sanity\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"DEFAULT\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-android-pfq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}"
-        ],
-        "luci_builder": "Try",
-        "manifest": "official.xml",
-        "uprev": true,
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
     "heli-factory-rambi-6420.B-factorybranch": {
         "_template": "factorybranch",
         "boards": [
@@ -17155,7 +16916,6 @@
         "boards": [
             "herobrine"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "herobrine-release-tryjob": {
@@ -17179,7 +16939,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "herobrine-unittest-stress": {
@@ -17217,11 +16976,32 @@
         "suite_scheduling": false,
         "workspace_branch": "factory-kukui-12587.B"
     },
+    "jacuzzi-factory-kukui-14374.B-factorybranch": {
+        "_template": "factorybranch",
+        "boards": [
+            "jacuzzi"
+        ],
+        "workspace_branch": "factory-kukui-14374.B"
+    },
+    "jacuzzi-factory-kukui-14374.B-factorybranch-tryjob": {
+        "_template": "factorybranch",
+        "boards": [
+            "jacuzzi"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "push_image": false,
+        "suite_scheduling": false,
+        "workspace_branch": "factory-kukui-14374.B"
+    },
     "jacuzzi-full": {
         "_template": "full",
         "boards": [
             "jacuzzi"
         ],
+        "manifest_version": true,
         "prebuilts": "public",
         "run_cpeexport": true,
         "useflags": [
@@ -17247,6 +17027,7 @@
         ],
         "hw_tests_override": null,
         "luci_builder": "Try",
+        "manifest_version": true,
         "prebuilts": "public",
         "run_cpeexport": true,
         "useflags": [
@@ -17358,10 +17139,10 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"jacuzzi\",\n    \"name\": \"kenzo\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"jacuzzi\",\n    \"name\": \"makomo\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"jacuzzi\",\n    \"name\": \"pico\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"jacuzzi\",\n    \"name\": \"pico6\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"jacuzzi\",\n    \"name\": \"stern\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"jacuzzi\",\n    \"name\": \"willow\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "jacuzzi-kernelnext-release-tryjob": {
@@ -17396,13 +17177,13 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"jacuzzi\",\n    \"name\": \"kenzo\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"jacuzzi\",\n    \"name\": \"makomo\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"jacuzzi\",\n    \"name\": \"pico\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"jacuzzi\",\n    \"name\": \"pico6\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"jacuzzi\",\n    \"name\": \"stern\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"jacuzzi\",\n    \"name\": \"willow\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "jacuzzi-kernelnext-unittest-stress": {
@@ -17486,6 +17267,7 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"jacuzzi\",\n    \"name\": \"kenzo\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"jacuzzi\",\n    \"name\": \"makomo\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"jacuzzi\",\n    \"name\": \"pico\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"jacuzzi\",\n    \"name\": \"pico6\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"jacuzzi\",\n    \"name\": \"stern\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"jacuzzi\",\n    \"name\": \"willow\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
@@ -17493,7 +17275,6 @@
             "recovery",
             "factory"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "jacuzzi-release-tryjob": {
@@ -17528,6 +17309,7 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"jacuzzi\",\n    \"name\": \"kenzo\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"jacuzzi\",\n    \"name\": \"makomo\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"jacuzzi\",\n    \"name\": \"pico\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"jacuzzi\",\n    \"name\": \"pico6\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"jacuzzi\",\n    \"name\": \"stern\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"jacuzzi\",\n    \"name\": \"willow\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
@@ -17538,7 +17320,6 @@
             "factory"
         ],
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "jacuzzi-unittest-stress": {
@@ -17645,7 +17426,6 @@
         "boards": [
             "jecht"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "jecht-release-tryjob": {
@@ -17669,7 +17449,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "jecht-unittest-stress": {
@@ -17780,7 +17559,6 @@
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"kalista\",\n    \"name\": \"karma\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "kalista-cfm-release-tryjob": {
@@ -17807,7 +17585,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "kalista-cfm-unittest-stress": {
@@ -17937,7 +17714,6 @@
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"kalista\",\n    \"name\": \"karma\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "kalista-release-tryjob": {
@@ -17964,7 +17740,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "kalista-unittest-stress": {
@@ -18091,23 +17866,19 @@
         "boards": [
             "keeby"
         ],
-        "hw_tests": [],
-        "hw_tests_disabled_bug": "b/185377942",
-        "hw_tests_override": [],
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"keeby\",\n    \"name\": \"cappy2\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"keeby\",\n    \"name\": \"corori\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"keeby\",\n    \"name\": \"driblee\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"keeby\",\n    \"name\": \"gooey\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"keeby\",\n    \"name\": \"habokay\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"keeby\",\n    \"name\": \"haboki\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"keeby\",\n    \"name\": \"gooey\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"keeby\",\n    \"name\": \"habokay\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"keeby\",\n    \"name\": \"haboki\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"keeby\",\n    \"name\": \"lalala\",\n    \"test_suites\": []\n}"
         ],
         "sign_types": [
             "recovery",
             "factory"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "keeby-release-tryjob": {
@@ -18117,17 +17888,24 @@
         ],
         "debug": true,
         "display_label": "tryjob",
-        "hw_tests": [],
-        "hw_tests_disabled_bug": "b/185377942",
+        "hw_tests": [
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
+        ],
         "hw_tests_override": null,
         "luci_builder": "Try",
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"keeby\",\n    \"name\": \"cappy2\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"keeby\",\n    \"name\": \"corori\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"keeby\",\n    \"name\": \"driblee\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"keeby\",\n    \"name\": \"gooey\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"keeby\",\n    \"name\": \"habokay\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"keeby\",\n    \"name\": \"haboki\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"keeby\",\n    \"name\": \"gooey\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"keeby\",\n    \"name\": \"habokay\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"keeby\",\n    \"name\": \"haboki\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"keeby\",\n    \"name\": \"lalala\",\n    \"test_suites\": []\n}"
         ],
         "paygen": false,
@@ -18137,7 +17915,6 @@
             "factory"
         ],
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "keeby-unittest-stress": {
@@ -18285,7 +18062,6 @@
             "kefka"
         ],
         "chrome_sdk_build_chrome": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "kefka-release-tryjob": {
@@ -18310,7 +18086,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "kefka-unittest-stress": {
@@ -18328,78 +18103,6 @@
             "chrome_internal"
         ]
     },
-    "kernel-3_18-release-afdo-verify": {
-        "_template": "release_afdo_verify",
-        "boards": [
-            "chell"
-        ],
-        "kernel_afdo_verify": true
-    },
-    "kernel-3_18-release-afdo-verify-tryjob": {
-        "_template": "release_afdo_verify",
-        "boards": [
-            "chell"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests_override": null,
-        "kernel_afdo_verify": true,
-        "luci_builder": "Try"
-    },
-    "kernel-4_14-release-afdo-verify": {
-        "_template": "release_afdo_verify",
-        "boards": [
-            "octopus"
-        ],
-        "kernel_afdo_verify": true
-    },
-    "kernel-4_14-release-afdo-verify-tryjob": {
-        "_template": "release_afdo_verify",
-        "boards": [
-            "octopus"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests_override": null,
-        "kernel_afdo_verify": true,
-        "luci_builder": "Try"
-    },
-    "kernel-4_19-release-afdo-verify": {
-        "_template": "release_afdo_verify",
-        "boards": [
-            "banon"
-        ],
-        "kernel_afdo_verify": true
-    },
-    "kernel-4_19-release-afdo-verify-tryjob": {
-        "_template": "release_afdo_verify",
-        "boards": [
-            "banon"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests_override": null,
-        "kernel_afdo_verify": true,
-        "luci_builder": "Try"
-    },
-    "kernel-4_4-release-afdo-verify": {
-        "_template": "release_afdo_verify",
-        "boards": [
-            "eve"
-        ],
-        "kernel_afdo_verify": true
-    },
-    "kernel-4_4-release-afdo-verify-tryjob": {
-        "_template": "release_afdo_verify",
-        "boards": [
-            "eve"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests_override": null,
-        "kernel_afdo_verify": true,
-        "luci_builder": "Try"
-    },
     "kevin-android-pi-pre-flight-branch": {
         "_template": "pre_flight_branch",
         "android_import_branch": "git_pi-arc",
@@ -18576,7 +18279,9 @@
         "boards": [
             "kevin-kernelnext"
         ],
-        "vm_tests": [],
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"kevin\",\n    \"name\": \"kevin\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
+        ],
         "vm_tests_override": null
     },
     "kevin-kernelnext-release-tryjob": {
@@ -18597,10 +18302,12 @@
         ],
         "hw_tests_override": null,
         "luci_builder": "Try",
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"kevin\",\n    \"name\": \"kevin\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
+        ],
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "kevin-kernelnext-unittest-stress": {
@@ -18681,54 +18388,14 @@
         "hw_tests_override": null,
         "luci_builder": "Try"
     },
-    "kevin-pi-android-pfq": {
-        "_template": "pi_android_pfq",
-        "boards": [
-            "kevin"
-        ],
-        "enable_skylab_hw_tests": true,
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": true,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": true,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"pfq\",\n    \"retry\": true,\n    \"suite\": \"sanity\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": true,\n    \"max_retries\": 5,\n    \"minimum_duts\": 3,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PFQ\",\n    \"quota_account\": \"pfq\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 3,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": true,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PFQ\",\n    \"quota_account\": \"pfq\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-android-pfq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}"
-        ],
-        "manifest": "official.xml",
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
-    "kevin-pi-android-pfq-tryjob": {
-        "_template": "pi_android_pfq",
-        "boards": [
-            "kevin"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "enable_skylab_hw_tests": true,
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "manifest": "official.xml",
-        "uprev": true,
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
     "kevin-release": {
         "_template": "release",
         "boards": [
             "kevin"
         ],
-        "chrome_sdk_build_chrome": false,
-        "vm_tests": [],
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"kevin\",\n    \"name\": \"kevin\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
+        ],
         "vm_tests_override": null
     },
     "kevin-release-tryjob": {
@@ -18736,7 +18403,6 @@
         "boards": [
             "kevin"
         ],
-        "chrome_sdk_build_chrome": false,
         "debug": true,
         "display_label": "tryjob",
         "hw_tests": [
@@ -18750,10 +18416,12 @@
         ],
         "hw_tests_override": null,
         "luci_builder": "Try",
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"kevin\",\n    \"name\": \"kevin\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
+        ],
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "kevin-unittest-stress": {
@@ -18861,7 +18529,10 @@
             "kevin-userdebug"
         ],
         "important": false,
-        "vm_tests": [],
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"kevin\",\n    \"name\": \"kevin\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"kevin\",\n    \"name\": \"kevin1\",\n    \"test_suites\": []\n}"
+        ],
         "vm_tests_override": null
     },
     "kevin-userdebug-release-tryjob": {
@@ -18882,10 +18553,13 @@
         ],
         "hw_tests_override": null,
         "luci_builder": "Try",
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"kevin\",\n    \"name\": \"kevin\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"kevin\",\n    \"name\": \"kevin1\",\n    \"test_suites\": []\n}"
+        ],
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "kevin-userdebug-unittest-stress": {
@@ -18997,7 +18671,9 @@
             "kevin64"
         ],
         "important": false,
-        "vm_tests": [],
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"kevin\",\n    \"name\": \"kevin\",\n    \"test_suites\": []\n}"
+        ],
         "vm_tests_override": null
     },
     "kevin64-release-tryjob": {
@@ -19018,10 +18694,12 @@
         ],
         "hw_tests_override": null,
         "luci_builder": "Try",
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"kevin\",\n    \"name\": \"kevin\",\n    \"test_suites\": []\n}"
+        ],
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "kevin64-unittest-stress": {
@@ -19216,7 +18894,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"kukui\",\n    \"name\": \"krane\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"kukui\",\n    \"name\": \"kukui\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "kukui-arc-r-release-tryjob": {
@@ -19247,7 +18924,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "kukui-arc-r-unittest-stress": {
@@ -19265,44 +18941,6 @@
             "chrome_internal"
         ]
     },
-    "kukui-arc-r-vmrvc-android-pfq": {
-        "_template": "vmrvc_android_pfq",
-        "boards": [
-            "kukui-arc-r"
-        ],
-        "enable_skylab_hw_tests": true,
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": true,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": true,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"pfq\",\n    \"retry\": true,\n    \"suite\": \"sanity\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": true,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PFQ\",\n    \"quota_account\": \"pfq\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-android-pfq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": [
-            "{\n    \"async\": false,\n    \"blocking\": true,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"DEFAULT\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"sanity\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"DEFAULT\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-android-pfq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}"
-        ],
-        "manifest": "official.xml",
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
-    "kukui-arc-r-vmrvc-android-pfq-tryjob": {
-        "_template": "vmrvc_android_pfq",
-        "boards": [
-            "kukui-arc-r"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "enable_skylab_hw_tests": true,
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": true,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"DEFAULT\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"sanity\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"DEFAULT\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-android-pfq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}"
-        ],
-        "luci_builder": "Try",
-        "manifest": "official.xml",
-        "uprev": true,
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
     "kukui-factory-kukui-12587.B-factorybranch": {
         "_template": "factorybranch",
         "boards": [
@@ -19323,6 +18961,26 @@
         "suite_scheduling": false,
         "workspace_branch": "factory-kukui-12587.B"
     },
+    "kukui-factory-kukui-14374.B-factorybranch": {
+        "_template": "factorybranch",
+        "boards": [
+            "kukui"
+        ],
+        "workspace_branch": "factory-kukui-14374.B"
+    },
+    "kukui-factory-kukui-14374.B-factorybranch-tryjob": {
+        "_template": "factorybranch",
+        "boards": [
+            "kukui"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "push_image": false,
+        "suite_scheduling": false,
+        "workspace_branch": "factory-kukui-14374.B"
+    },
     "kukui-full": {
         "_template": "full",
         "boards": [
@@ -19457,7 +19115,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"kukui\",\n    \"name\": \"krane\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"kukui\",\n    \"name\": \"kukui\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "kukui-kernelnext-release-tryjob": {
@@ -19488,7 +19145,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "kukui-kernelnext-unittest-stress": {
@@ -19568,7 +19224,6 @@
             "recovery",
             "factory"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "kukui-release-tryjob": {
@@ -19602,7 +19257,6 @@
             "factory"
         ],
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "kukui-unittest-stress": {
@@ -19788,7 +19442,6 @@
         ],
         "chrome_sdk_build_chrome": false,
         "important": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "lars-kernelnext-release-tryjob": {
@@ -19813,7 +19466,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "lars-kernelnext-unittest-stress": {
@@ -19883,7 +19535,6 @@
         "boards": [
             "lars"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "lars-release-tryjob": {
@@ -19907,7 +19558,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "lars-unittest-stress": {
@@ -20087,7 +19737,6 @@
         "suite_scheduling": false,
         "sync_chrome": false,
         "upload_hw_test_artifacts": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "littlejoe-release": {
@@ -20112,7 +19761,6 @@
         "signer_tests": false,
         "sync_chrome": false,
         "upload_hw_test_artifacts": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "littlejoe-release-tryjob": {
@@ -20142,7 +19790,6 @@
         "suite_scheduling": false,
         "sync_chrome": false,
         "upload_hw_test_artifacts": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "littlejoe-unittest-stress": {
@@ -20349,7 +19996,6 @@
         ],
         "important": false,
         "unittests": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "majolica-release-tryjob": {
@@ -20374,7 +20020,6 @@
         "push_image": false,
         "suite_scheduling": false,
         "unittests": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "majolica-unittest-stress": {
@@ -20488,7 +20133,6 @@
             "mancomb"
         ],
         "unittests": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "mancomb-release-tryjob": {
@@ -20513,7 +20157,6 @@
         "push_image": false,
         "suite_scheduling": false,
         "unittests": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "mancomb-unittest-stress": {
@@ -20581,10 +20224,13 @@
             "arm64-generic-full",
             "eve-full",
             "hana-full",
+            "jacuzzi-full",
             "kevin-full",
             "kevin64-full",
+            "octopus-full",
             "tael-full",
-            "tatl-full"
+            "tatl-full",
+            "zork-full"
         ],
         "useflags": [
             "-chrome_internal"
@@ -20619,106 +20265,18 @@
             "arm64-generic-full-tryjob",
             "eve-full-tryjob",
             "hana-full-tryjob",
+            "jacuzzi-full-tryjob",
             "kevin-full-tryjob",
             "kevin64-full-tryjob",
+            "octopus-full-tryjob",
             "tael-full-tryjob",
-            "tatl-full-tryjob"
+            "tatl-full-tryjob",
+            "zork-full-tryjob"
         ],
         "useflags": [
             "-chrome_internal"
         ]
     },
-    "master-incremental": {
-        "_template": "incremental",
-        "boards": [],
-        "description": "Incremental Builds (internal)",
-        "internal": true,
-        "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
-        "manifest_version": true,
-        "master": true,
-        "overlays": "both",
-        "schedule": "with 10m interval",
-        "slave_configs": [
-            "amd64-generic-incremental",
-            "betty-incremental",
-            "chell-incremental"
-        ]
-    },
-    "master-incremental-tryjob": {
-        "_template": "incremental",
-        "boards": [],
-        "chroot_replace": true,
-        "debug": true,
-        "debug_cidb": true,
-        "description": "Incremental Builds (internal)",
-        "display_label": "tryjob",
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "internal": true,
-        "luci_builder": "Try",
-        "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
-        "manifest_version": true,
-        "master": true,
-        "overlays": "both",
-        "slave_configs": [
-            "amd64-generic-incremental-tryjob",
-            "betty-incremental-tryjob",
-            "chell-incremental-tryjob"
-        ],
-        "uprev": true
-    },
-    "master-pi-android-pfq": {
-        "_template": "pi_android_pfq",
-        "boards": [],
-        "build_timeout": 36000,
-        "master": true,
-        "push_overlays": "both",
-        "schedule": "with 60m interval",
-        "slave_configs": [
-            "betty-pi-arc-pi-android-pfq",
-            "coral-pi-android-pfq",
-            "grunt-pi-android-pfq",
-            "kevin-pi-android-pfq",
-            "rammus-pi-android-pfq"
-        ]
-    },
-    "master-pi-android-pfq-tryjob": {
-        "_template": "pi_android_pfq",
-        "boards": [],
-        "build_timeout": 36000,
-        "debug": true,
-        "debug_cidb": true,
-        "display_label": "tryjob",
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "master": true,
-        "push_overlays": "both",
-        "slave_configs": [
-            "betty-pi-arc-pi-android-pfq-tryjob",
-            "coral-pi-android-pfq-tryjob",
-            "grunt-pi-android-pfq-tryjob",
-            "kevin-pi-android-pfq-tryjob",
-            "rammus-pi-android-pfq-tryjob"
-        ],
-        "uprev": true
-    },
     "master-release": {
         "_template": "release",
         "boards": [],
@@ -20731,7 +20289,6 @@
             "asuka-release",
             "asurada-connectivitynext-release",
             "asurada-release",
-            "asurada-zephyr-release",
             "atlas-blueznext-release",
             "atlas-connectivitynext-release",
             "atlas-kernelnext-release",
@@ -20740,7 +20297,6 @@
             "aurora-release",
             "banon-release",
             "beaglebone-release",
-            "beaglebone_servo-release",
             "betty-arc-r-release",
             "betty-arc-s-release",
             "betty-arc-t-release",
@@ -20749,11 +20305,12 @@
             "betty-release",
             "bob-release",
             "brask-release",
+            "brya-lvm-stateful-release",
             "brya-manatee-release",
             "brya-release",
+            "brya-zephyr-release",
             "bubs-release",
             "caroline-arc64-release",
-            "caroline-kernelnext-release",
             "caroline-ndktranslation-release",
             "caroline-release",
             "caroline-userdebug-release",
@@ -20761,10 +20318,13 @@
             "celes-release",
             "chell-release",
             "cherry-release",
+            "cherry64-release",
             "coral-kernelnext-release",
             "coral-release",
+            "corsola-release",
             "cyan-release",
             "dedede-release",
+            "draco-release",
             "drallion-release",
             "edgar-release",
             "elm-arc64-release",
@@ -20774,16 +20334,15 @@
             "endeavour-release",
             "eve-arc-r-release",
             "eve-arm64-release",
-            "eve-kernelnext-release",
             "eve-kvm-release",
             "eve-release",
             "eve-userdebug-release",
             "excelsior-release",
             "fizz-cfm-release",
+            "fizz-kernelnext-release",
             "fizz-labstation-release",
             "fizz-moblab-release",
             "fizz-release",
-            "gale-release",
             "goroh-release",
             "grunt-arc-r-release",
             "grunt-kernelnext-release",
@@ -20798,12 +20357,12 @@
             "hatch-arc-r-release",
             "hatch-arc-r-userdebug-release",
             "hatch-arc-s-release",
+            "hatch-arc-t-release",
             "hatch-blueznext-release",
             "hatch-borealis-release",
             "hatch-connectivitynext-release",
             "hatch-diskswap-release",
             "hatch-kernelnext-release",
-            "hatch-manatee-release",
             "hatch-release",
             "herobrine-release",
             "jacuzzi-kernelnext-release",
@@ -20822,7 +20381,6 @@
             "lars-kernelnext-release",
             "lars-release",
             "majolica-release",
-            "mistral-release",
             "mushu-release",
             "nami-kernelnext-release",
             "nami-release",
@@ -20853,15 +20411,21 @@
             "sand-release",
             "sarien-kernelnext-release",
             "sarien-release",
+            "scarlet-kernelnext-release",
             "scarlet-release",
             "senor-release",
             "sentry-release",
             "setzer-release",
             "shadowkeep-release",
+            "skolas-release",
+            "skyrim-chausie-release",
+            "skyrim-kernelnext-release",
+            "skyrim-release",
             "snappy-kernelnext-release",
             "snappy-release",
             "soraka-libcamera-release",
             "soraka-release",
+            "strongbad-kernelnext-release",
             "strongbad-release",
             "tael-release",
             "tatl-release",
@@ -20873,14 +20437,10 @@
             "trogdor-zephyr-release",
             "trogdor64-release",
             "ultima-release",
-            "veyron_fievel-release",
-            "veyron_rialto-release",
-            "veyron_tiger-release",
             "volteer-borealis-release",
             "volteer-kernelnext-release",
             "volteer-manatee-release",
             "volteer-release",
-            "volteer-zephyr-release",
             "wizpig-release",
             "zork-arc-r-release",
             "zork-borealis-release",
@@ -20950,7 +20510,6 @@
             "asuka-release-tryjob",
             "asurada-connectivitynext-release-tryjob",
             "asurada-release-tryjob",
-            "asurada-zephyr-release-tryjob",
             "atlas-blueznext-release-tryjob",
             "atlas-connectivitynext-release-tryjob",
             "atlas-kernelnext-release-tryjob",
@@ -20959,7 +20518,6 @@
             "aurora-release-tryjob",
             "banon-release-tryjob",
             "beaglebone-release-tryjob",
-            "beaglebone_servo-release-tryjob",
             "betty-arc-r-release-tryjob",
             "betty-arc-s-release-tryjob",
             "betty-arc-t-release-tryjob",
@@ -20968,11 +20526,12 @@
             "betty-release-tryjob",
             "bob-release-tryjob",
             "brask-release-tryjob",
+            "brya-lvm-stateful-release-tryjob",
             "brya-manatee-release-tryjob",
             "brya-release-tryjob",
+            "brya-zephyr-release-tryjob",
             "bubs-release-tryjob",
             "caroline-arc64-release-tryjob",
-            "caroline-kernelnext-release-tryjob",
             "caroline-ndktranslation-release-tryjob",
             "caroline-release-tryjob",
             "caroline-userdebug-release-tryjob",
@@ -20980,10 +20539,13 @@
             "celes-release-tryjob",
             "chell-release-tryjob",
             "cherry-release-tryjob",
+            "cherry64-release-tryjob",
             "coral-kernelnext-release-tryjob",
             "coral-release-tryjob",
+            "corsola-release-tryjob",
             "cyan-release-tryjob",
             "dedede-release-tryjob",
+            "draco-release-tryjob",
             "drallion-release-tryjob",
             "edgar-release-tryjob",
             "elm-arc64-release-tryjob",
@@ -20993,16 +20555,15 @@
             "endeavour-release-tryjob",
             "eve-arc-r-release-tryjob",
             "eve-arm64-release-tryjob",
-            "eve-kernelnext-release-tryjob",
             "eve-kvm-release-tryjob",
             "eve-release-tryjob",
             "eve-userdebug-release-tryjob",
             "excelsior-release-tryjob",
             "fizz-cfm-release-tryjob",
+            "fizz-kernelnext-release-tryjob",
             "fizz-labstation-release-tryjob",
             "fizz-moblab-release-tryjob",
             "fizz-release-tryjob",
-            "gale-release-tryjob",
             "goroh-release-tryjob",
             "grunt-arc-r-release-tryjob",
             "grunt-kernelnext-release-tryjob",
@@ -21017,12 +20578,12 @@
             "hatch-arc-r-release-tryjob",
             "hatch-arc-r-userdebug-release-tryjob",
             "hatch-arc-s-release-tryjob",
+            "hatch-arc-t-release-tryjob",
             "hatch-blueznext-release-tryjob",
             "hatch-borealis-release-tryjob",
             "hatch-connectivitynext-release-tryjob",
             "hatch-diskswap-release-tryjob",
             "hatch-kernelnext-release-tryjob",
-            "hatch-manatee-release-tryjob",
             "hatch-release-tryjob",
             "herobrine-release-tryjob",
             "jacuzzi-kernelnext-release-tryjob",
@@ -21041,7 +20602,6 @@
             "lars-kernelnext-release-tryjob",
             "lars-release-tryjob",
             "majolica-release-tryjob",
-            "mistral-release-tryjob",
             "mushu-release-tryjob",
             "nami-kernelnext-release-tryjob",
             "nami-release-tryjob",
@@ -21072,15 +20632,21 @@
             "sand-release-tryjob",
             "sarien-kernelnext-release-tryjob",
             "sarien-release-tryjob",
+            "scarlet-kernelnext-release-tryjob",
             "scarlet-release-tryjob",
             "senor-release-tryjob",
             "sentry-release-tryjob",
             "setzer-release-tryjob",
             "shadowkeep-release-tryjob",
+            "skolas-release-tryjob",
+            "skyrim-chausie-release-tryjob",
+            "skyrim-kernelnext-release-tryjob",
+            "skyrim-release-tryjob",
             "snappy-kernelnext-release-tryjob",
             "snappy-release-tryjob",
             "soraka-libcamera-release-tryjob",
             "soraka-release-tryjob",
+            "strongbad-kernelnext-release-tryjob",
             "strongbad-release-tryjob",
             "tael-release-tryjob",
             "tatl-release-tryjob",
@@ -21092,14 +20658,10 @@
             "trogdor-zephyr-release-tryjob",
             "trogdor64-release-tryjob",
             "ultima-release-tryjob",
-            "veyron_fievel-release-tryjob",
-            "veyron_rialto-release-tryjob",
-            "veyron_tiger-release-tryjob",
             "volteer-borealis-release-tryjob",
             "volteer-kernelnext-release-tryjob",
             "volteer-manatee-release-tryjob",
             "volteer-release-tryjob",
-            "volteer-zephyr-release-tryjob",
             "wizpig-release-tryjob",
             "zork-arc-r-release-tryjob",
             "zork-borealis-release-tryjob",
@@ -21113,90 +20675,6 @@
         "sync_chrome": true,
         "vm_tests_override": null
     },
-    "master-vmrvc-android-pfq": {
-        "_template": "vmrvc_android_pfq",
-        "boards": [],
-        "master": true,
-        "push_overlays": "both",
-        "schedule": "with 60m interval",
-        "slave_configs": [
-            "eve-arc-r-vmrvc-android-pfq",
-            "grunt-arc-r-vmrvc-android-pfq",
-            "hatch-vmrvc-android-pfq",
-            "kukui-arc-r-vmrvc-android-pfq",
-            "rammus-arc-r-vmrvc-android-pfq",
-            "zork-arc-r-vmrvc-android-pfq"
-        ]
-    },
-    "master-vmrvc-android-pfq-tryjob": {
-        "_template": "vmrvc_android_pfq",
-        "boards": [],
-        "debug": true,
-        "debug_cidb": true,
-        "display_label": "tryjob",
-        "luci_builder": "Try",
-        "master": true,
-        "push_overlays": "both",
-        "slave_configs": [
-            "eve-arc-r-vmrvc-android-pfq-tryjob",
-            "grunt-arc-r-vmrvc-android-pfq-tryjob",
-            "hatch-vmrvc-android-pfq-tryjob",
-            "kukui-arc-r-vmrvc-android-pfq-tryjob",
-            "rammus-arc-r-vmrvc-android-pfq-tryjob",
-            "zork-arc-r-vmrvc-android-pfq-tryjob"
-        ],
-        "uprev": true
-    },
-    "master-vmsc-android-pfq": {
-        "_template": "vmsc_android_pfq",
-        "boards": [],
-        "master": true,
-        "push_overlays": "both",
-        "schedule": "with 60m interval",
-        "slave_configs": [
-            "betty-arc-s-vmsc-android-pfq",
-            "hatch-arc-s-vmsc-android-pfq"
-        ]
-    },
-    "master-vmsc-android-pfq-tryjob": {
-        "_template": "vmsc_android_pfq",
-        "boards": [],
-        "debug": true,
-        "debug_cidb": true,
-        "display_label": "tryjob",
-        "luci_builder": "Try",
-        "master": true,
-        "push_overlays": "both",
-        "slave_configs": [
-            "betty-arc-s-vmsc-android-pfq-tryjob",
-            "hatch-arc-s-vmsc-android-pfq-tryjob"
-        ],
-        "uprev": true
-    },
-    "master-vmt-android-pfq": {
-        "_template": "vmt_android_pfq",
-        "boards": [],
-        "master": true,
-        "push_overlays": "both",
-        "schedule": "with 150m interval",
-        "slave_configs": [
-            "betty-arc-t-vmt-android-pfq"
-        ]
-    },
-    "master-vmt-android-pfq-tryjob": {
-        "_template": "vmt_android_pfq",
-        "boards": [],
-        "debug": true,
-        "debug_cidb": true,
-        "display_label": "tryjob",
-        "luci_builder": "Try",
-        "master": true,
-        "push_overlays": "both",
-        "slave_configs": [
-            "betty-arc-t-vmt-android-pfq-tryjob"
-        ],
-        "uprev": true
-    },
     "mistral-factory-mistral-12361.B-factorybranch": {
         "_template": "factorybranch",
         "boards": [
@@ -21217,105 +20695,6 @@
         "suite_scheduling": false,
         "workspace_branch": "factory-mistral-12361.B"
     },
-    "mistral-full": {
-        "_template": "full",
-        "boards": [
-            "mistral"
-        ],
-        "chrome_sdk": false,
-        "prebuilts": "public",
-        "run_cpeexport": true,
-        "sync_chrome": false,
-        "useflags": [
-            "-chrome_internal"
-        ],
-        "vm_tests": []
-    },
-    "mistral-full-tryjob": {
-        "_template": "full",
-        "boards": [
-            "mistral"
-        ],
-        "chrome_sdk": false,
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "prebuilts": "public",
-        "run_cpeexport": true,
-        "sync_chrome": false,
-        "useflags": [
-            "-chrome_internal"
-        ],
-        "vm_tests": []
-    },
-    "mistral-llvm-next-toolchain": {
-        "_template": "llvm_next_toolchain",
-        "boards": [
-            "mistral"
-        ],
-        "chrome_sdk": false,
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"toolchain\",\n    \"retry\": true,\n    \"suite\": \"jetstream_cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"toolchain\",\n    \"retry\": true,\n    \"suite\": \"jetstream_cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}"
-        ],
-        "sync_chrome": false
-    },
-    "mistral-llvm-next-toolchain-tryjob": {
-        "_template": "llvm_next_toolchain",
-        "boards": [
-            "mistral"
-        ],
-        "chrome_sdk": false,
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"toolchain\",\n    \"retry\": true,\n    \"suite\": \"jetstream_cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "sync_chrome": false
-    },
-    "mistral-llvm-toolchain": {
-        "_template": "llvm_toolchain",
-        "boards": [
-            "mistral"
-        ],
-        "chrome_sdk": false,
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"toolchain\",\n    \"retry\": true,\n    \"suite\": \"jetstream_cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"toolchain\",\n    \"retry\": true,\n    \"suite\": \"jetstream_cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}"
-        ],
-        "sync_chrome": false
-    },
-    "mistral-llvm-toolchain-tryjob": {
-        "_template": "llvm_toolchain",
-        "boards": [
-            "mistral"
-        ],
-        "chrome_sdk": false,
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"toolchain\",\n    \"retry\": true,\n    \"suite\": \"jetstream_cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "sync_chrome": false
-    },
     "mistral-master-factorybranch": {
         "_template": "factorybranch",
         "boards": [
@@ -21336,72 +20715,6 @@
         "suite_scheduling": false,
         "workspace_branch": "master"
     },
-    "mistral-payloads": {
-        "_template": "payloads",
-        "boards": [
-            "mistral"
-        ]
-    },
-    "mistral-payloads-tryjob": {
-        "_template": "payloads",
-        "boards": [
-            "mistral"
-        ],
-        "debug": true,
-        "hw_tests_override": null,
-        "luci_builder": "Try"
-    },
-    "mistral-release": {
-        "_template": "release",
-        "boards": [
-            "mistral"
-        ],
-        "chrome_sdk": false,
-        "hw_tests": [],
-        "hw_tests_disabled_bug": "https://b/140317527",
-        "hw_tests_override": [],
-        "important": false,
-        "paygen_skip_testing": true,
-        "sync_chrome": false,
-        "vm_tests": [],
-        "vm_tests_override": null
-    },
-    "mistral-release-tryjob": {
-        "_template": "release",
-        "boards": [
-            "mistral"
-        ],
-        "chrome_sdk": false,
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests": [],
-        "hw_tests_disabled_bug": "https://b/140317527",
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "paygen": false,
-        "paygen_skip_testing": true,
-        "push_image": false,
-        "suite_scheduling": false,
-        "sync_chrome": false,
-        "vm_tests": [],
-        "vm_tests_override": null
-    },
-    "mistral-unittest-stress": {
-        "_template": "unittest_stress",
-        "boards": [
-            "mistral"
-        ],
-        "hw_tests_override": null,
-        "internal": true,
-        "luci_builder": "Try",
-        "manifest": "official.xml",
-        "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
-        "overlays": "both",
-        "sync_chrome": false,
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
     "moblab-generic-vm-full": {
         "_template": "full",
         "boards": [
@@ -21585,7 +20898,6 @@
             "recovery",
             "factory"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "mushu-release-tryjob": {
@@ -21609,7 +20921,6 @@
             "factory"
         ],
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "mushu-unittest-stress": {
@@ -21785,7 +21096,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"nami\",\n    \"name\": \"syndra\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"nami\",\n    \"name\": \"vayne\",\n    \"test_suites\": [\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "nami-kernelnext-release-tryjob": {
@@ -21820,7 +21130,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "nami-kernelnext-unittest-stress": {
@@ -21901,7 +21210,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"nami\",\n    \"name\": \"syndra\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"nami\",\n    \"name\": \"vayne\",\n    \"test_suites\": [\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "nami-release-tryjob": {
@@ -21936,7 +21244,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "nami-unittest-stress": {
@@ -22067,7 +21374,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"nautilus\",\n    \"name\": \"nautilus\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"nautilus\",\n    \"name\": \"nautiluslte\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "nautilus-release-tryjob": {
@@ -22095,7 +21401,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "nautilus-unittest-stress": {
@@ -22242,7 +21547,6 @@
         "boards": [
             "nissa"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "nissa-release-tryjob": {
@@ -22266,7 +21570,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "nissa-unittest-stress": {
@@ -22434,7 +21737,6 @@
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"nocturne\",\n    \"name\": \"nocturne\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "nocturne-kernelnext-release-tryjob": {
@@ -22461,7 +21763,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "nocturne-kernelnext-unittest-stress": {
@@ -22537,9 +21838,9 @@
         "useflags": [
             "-cros-debug",
             "chrome_internal",
-            "goma_thinlto"
+            "goma_thinlto",
+            "thinlto"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "nocturne-release-tryjob": {
@@ -22569,9 +21870,9 @@
         "useflags": [
             "-cros-debug",
             "chrome_internal",
-            "goma_thinlto"
+            "goma_thinlto",
+            "thinlto"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "nocturne-unittest-stress": {
@@ -22800,7 +22101,10 @@
         ],
         "hw_tests": [],
         "hw_tests_disabled_bug": "https://crbug.com/1000717",
-        "hw_tests_override": []
+        "hw_tests_override": [],
+        "tast_vm_tests": [
+            "{\n    \"suite_name\": \"tast_vm_canary_critical\",\n    \"test_exprs\": [\n        \"(\\\"group:mainline\\\" && !informational)\"\n    ],\n    \"timeout\": 7200\n}"
+        ]
     },
     "novato-release-tryjob": {
         "_template": "release",
@@ -22816,6 +22120,9 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
+        "tast_vm_tests": [
+            "{\n    \"suite_name\": \"tast_vm_canary_critical\",\n    \"test_exprs\": [\n        \"(\\\"group:mainline\\\" && !informational)\"\n    ],\n    \"timeout\": 7200\n}"
+        ],
         "vm_tests_override": null
     },
     "novato-unittest-stress": {
@@ -22922,7 +22229,6 @@
         "boards": [
             "nyan_big"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "nyan_big-release-tryjob": {
@@ -22946,7 +22252,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "nyan_big-unittest-stress": {
@@ -23053,7 +22358,6 @@
         "boards": [
             "nyan_blaze"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "nyan_blaze-release-tryjob": {
@@ -23077,7 +22381,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "nyan_blaze-unittest-stress": {
@@ -23187,6 +22490,7 @@
         "important": false,
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"ampton\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"amptone\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"apel\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"apele\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"bloog\",\n    \"test_suites\": []\n}",
@@ -23232,7 +22536,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"vortininja\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"yorp\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "octopus-arc-r-release-tryjob": {
@@ -23255,6 +22558,7 @@
         "luci_builder": "Try",
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"ampton\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"amptone\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"apel\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"apele\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"bloog\",\n    \"test_suites\": []\n}",
@@ -23303,7 +22607,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "octopus-arc-r-unittest-stress": {
@@ -23346,6 +22649,7 @@
         "boards": [
             "octopus"
         ],
+        "manifest_version": true,
         "prebuilts": "public",
         "run_cpeexport": true,
         "useflags": [
@@ -23371,6 +22675,7 @@
         ],
         "hw_tests_override": null,
         "luci_builder": "Try",
+        "manifest_version": true,
         "prebuilts": "public",
         "run_cpeexport": true,
         "useflags": [
@@ -23470,6 +22775,7 @@
         "important": false,
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"ampton\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"amptone\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"apel\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"apele\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"bloog\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
@@ -23504,7 +22810,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"vortininja\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"yorp\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "octopus-kernelnext-release-tryjob": {
@@ -23527,6 +22832,7 @@
         "luci_builder": "Try",
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"ampton\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"amptone\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"apel\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"apele\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"bloog\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
@@ -23564,7 +22870,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "octopus-kernelnext-unittest-stress": {
@@ -23656,8 +22961,8 @@
         ],
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"ampton\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"amptone\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"apel\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"apel-e\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"apele\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"bip\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"bloog\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
@@ -23693,7 +22998,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"vortininja\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"yorp\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "octopus-release-tryjob": {
@@ -23716,8 +23020,8 @@
         "luci_builder": "Try",
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"ampton\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"amptone\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"apel\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"apel-e\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"apele\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"bip\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"octopus\",\n    \"name\": \"bloog\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
@@ -23756,7 +23060,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "octopus-unittest-stress": {
@@ -23814,38 +23117,6 @@
         "suite_scheduling": false,
         "workspace_branch": "factory-rambi-6420.B"
     },
-    "orderfile-generate-toolchain": {
-        "_template": "orderfile_generate_toolchain",
-        "boards": [
-            "terra"
-        ]
-    },
-    "orderfile-generate-toolchain-tryjob": {
-        "_template": "orderfile_generate_toolchain",
-        "boards": [
-            "terra"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests_override": null,
-        "luci_builder": "Try"
-    },
-    "orderfile-verify-toolchain": {
-        "_template": "orderfile_verify_toolchain",
-        "boards": [
-            "eve"
-        ]
-    },
-    "orderfile-verify-toolchain-tryjob": {
-        "_template": "orderfile_verify_toolchain",
-        "boards": [
-            "eve"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests_override": null,
-        "luci_builder": "Try"
-    },
     "palkia-full": {
         "_template": "full",
         "boards": [
@@ -23949,7 +23220,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"palkia\",\n    \"name\": \"kohaku\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"palkia\",\n    \"name\": \"palkia\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "palkia-release-tryjob": {
@@ -23986,7 +23256,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "palkia-unittest-stress": {
@@ -24093,7 +23362,6 @@
         "boards": [
             "poppy"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "poppy-release-tryjob": {
@@ -24117,7 +23385,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "poppy-unittest-stress": {
@@ -24249,7 +23516,6 @@
         "notification_configs": [
             "{\n    \"email\": \"borealis-release-builder-alerts@google.com\",\n    \"template\": \"legacy_release\",\n    \"threshold\": 2\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "puff-borealis-release-tryjob": {
@@ -24285,7 +23551,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "puff-borealis-unittest-stress": {
@@ -24520,7 +23785,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"puff-macrophage\",\n    \"name\": \"wyvern\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"puff-macrophage\",\n    \"name\": \"wyvern_accelerator\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "puff-macrophage-release-tryjob": {
@@ -24556,7 +23820,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "puff-macrophage-unittest-stress": {
@@ -24684,7 +23947,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"puff-moblab\",\n    \"name\": \"wyvern_accelerator\",\n    \"test_suites\": []\n}"
         ],
         "signer_tests": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "puff-moblab-release-tryjob": {
@@ -24713,7 +23975,6 @@
         "push_image": false,
         "signer_tests": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "puff-moblab-unittest-stress": {
@@ -24765,7 +24026,6 @@
             "recovery",
             "factory"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "puff-release-tryjob": {
@@ -24803,7 +24063,6 @@
             "factory"
         ],
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "puff-unittest-stress": {
@@ -24933,7 +24192,6 @@
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"pyro\",\n    \"name\": \"pyro\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "pyro-release-tryjob": {
@@ -24960,7 +24218,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "pyro-unittest-stress": {
@@ -25072,7 +24329,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"rammus\",\n    \"name\": \"leona\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"rammus\",\n    \"name\": \"shyvana\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "rammus-arc-r-release-tryjob": {
@@ -25100,7 +24356,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "rammus-arc-r-unittest-stress": {
@@ -25212,7 +24467,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"rammus\",\n    \"name\": \"leona\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"rammus\",\n    \"name\": \"shyvana\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "rammus-arc-r-userdebug-release-tryjob": {
@@ -25240,7 +24494,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "rammus-arc-r-userdebug-unittest-stress": {
@@ -25258,44 +24511,6 @@
             "chrome_internal"
         ]
     },
-    "rammus-arc-r-vmrvc-android-pfq": {
-        "_template": "vmrvc_android_pfq",
-        "boards": [
-            "rammus-arc-r"
-        ],
-        "enable_skylab_hw_tests": true,
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": true,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": true,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"pfq\",\n    \"retry\": true,\n    \"suite\": \"sanity\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": true,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PFQ\",\n    \"quota_account\": \"pfq\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-android-pfq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": [
-            "{\n    \"async\": false,\n    \"blocking\": true,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"DEFAULT\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"sanity\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"DEFAULT\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-android-pfq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}"
-        ],
-        "manifest": "official.xml",
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
-    "rammus-arc-r-vmrvc-android-pfq-tryjob": {
-        "_template": "vmrvc_android_pfq",
-        "boards": [
-            "rammus-arc-r"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "enable_skylab_hw_tests": true,
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": true,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"DEFAULT\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"sanity\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"DEFAULT\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-android-pfq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}"
-        ],
-        "luci_builder": "Try",
-        "manifest": "official.xml",
-        "uprev": true,
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
     "rammus-factory-rammus-11289.B-factorybranch": {
         "_template": "factorybranch",
         "boards": [
@@ -25420,47 +24635,6 @@
         "hw_tests_override": null,
         "luci_builder": "Try"
     },
-    "rammus-pi-android-pfq": {
-        "_template": "pi_android_pfq",
-        "boards": [
-            "rammus"
-        ],
-        "enable_skylab_hw_tests": true,
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": true,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": true,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"pfq\",\n    \"retry\": true,\n    \"suite\": \"sanity\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": true,\n    \"max_retries\": 5,\n    \"minimum_duts\": 3,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PFQ\",\n    \"quota_account\": \"pfq\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 3,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": true,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PFQ\",\n    \"quota_account\": \"pfq\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-android-pfq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}"
-        ],
-        "manifest": "official.xml",
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
-    "rammus-pi-android-pfq-tryjob": {
-        "_template": "pi_android_pfq",
-        "boards": [
-            "rammus"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "enable_skylab_hw_tests": true,
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "manifest": "official.xml",
-        "uprev": true,
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
     "rammus-release": {
         "_template": "release",
         "boards": [
@@ -25470,7 +24644,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"rammus\",\n    \"name\": \"leona\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"rammus\",\n    \"name\": \"shyvana\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "rammus-release-tryjob": {
@@ -25498,7 +24671,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "rammus-unittest-stress": {
@@ -25630,7 +24802,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"reef\",\n    \"name\": \"basking\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"reef\",\n    \"name\": \"electro\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "reef-release-tryjob": {
@@ -25659,7 +24830,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "reef-unittest-stress": {
@@ -25807,7 +24977,6 @@
             "reks"
         ],
         "chrome_sdk_build_chrome": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "reks-release-tryjob": {
@@ -25832,7 +25001,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "reks-unittest-stress": {
@@ -25850,22 +25018,6 @@
             "chrome_internal"
         ]
     },
-    "release-afdo-profile-generate": {
-        "boards": [],
-        "build_type": "toolchain",
-        "builder_class_name": "release_profile_builders.ReleaseProfileMergeBuilder",
-        "description": "Generates merged AFDO profiles for select Chrome releases",
-        "display_label": "toolchain"
-    },
-    "release-afdo-profile-generate-tryjob": {
-        "boards": [],
-        "build_type": "toolchain",
-        "builder_class_name": "release_profile_builders.ReleaseProfileMergeBuilder",
-        "debug": true,
-        "description": "Generates merged AFDO profiles for select Chrome releases",
-        "display_label": "tryjob",
-        "luci_builder": "Try"
-    },
     "relm-factory-strago-7458.B-factorybranch": {
         "_template": "factorybranch",
         "boards": [
@@ -25996,7 +25148,6 @@
             "relm"
         ],
         "chrome_sdk_build_chrome": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "relm-release-tryjob": {
@@ -26021,7 +25172,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "relm-unittest-stress": {
@@ -26170,7 +25320,6 @@
             "test"
         ],
         "important": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "reven-release-tryjob": {
@@ -26197,7 +25346,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "reven-unittest-stress": {
@@ -26487,7 +25635,6 @@
             "rex"
         ],
         "important": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "rex-release-tryjob": {
@@ -26511,7 +25658,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "rex-unittest-stress": {
@@ -26681,7 +25827,6 @@
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"sand\",\n    \"name\": \"sand\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "sand-release-tryjob": {
@@ -26708,7 +25853,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "sand-unittest-stress": {
@@ -26874,12 +26018,11 @@
         ],
         "important": false,
         "models": [
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"sarien\",\n    \"name\": \"arcada\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"sarien\",\n    \"name\": \"arcada\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"sarien\",\n    \"name\": \"arcada_signed\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"sarien\",\n    \"name\": \"sarien\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"sarien\",\n    \"name\": \"sarien_signed\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "sarien-kernelnext-release-tryjob": {
@@ -26901,7 +26044,7 @@
         "hw_tests_override": null,
         "luci_builder": "Try",
         "models": [
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"sarien\",\n    \"name\": \"arcada\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"sarien\",\n    \"name\": \"arcada\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"sarien\",\n    \"name\": \"arcada_signed\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"sarien\",\n    \"name\": \"sarien\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"sarien\",\n    \"name\": \"sarien_signed\",\n    \"test_suites\": []\n}"
@@ -26909,7 +26052,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "sarien-kernelnext-unittest-stress": {
@@ -27009,7 +26151,6 @@
             "recovery",
             "factory"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "sarien-release-tryjob": {
@@ -27043,7 +26184,6 @@
             "factory"
         ],
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "sarien-unittest-stress": {
@@ -27118,6 +26258,146 @@
         ],
         "vm_tests": []
     },
+    "scarlet-kernelnext-full": {
+        "_template": "full",
+        "boards": [
+            "scarlet-kernelnext"
+        ],
+        "prebuilts": "public",
+        "run_cpeexport": true,
+        "useflags": [
+            "-chrome_internal"
+        ],
+        "vm_tests": []
+    },
+    "scarlet-kernelnext-full-tryjob": {
+        "_template": "full",
+        "boards": [
+            "scarlet-kernelnext"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests": [
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
+        ],
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "prebuilts": "public",
+        "run_cpeexport": true,
+        "useflags": [
+            "-chrome_internal"
+        ],
+        "vm_tests": []
+    },
+    "scarlet-kernelnext-llvm-next-toolchain": {
+        "_template": "llvm_next_toolchain",
+        "boards": [
+            "scarlet-kernelnext"
+        ]
+    },
+    "scarlet-kernelnext-llvm-next-toolchain-tryjob": {
+        "_template": "llvm_next_toolchain",
+        "boards": [
+            "scarlet-kernelnext"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "scarlet-kernelnext-llvm-toolchain": {
+        "_template": "llvm_toolchain",
+        "boards": [
+            "scarlet-kernelnext"
+        ]
+    },
+    "scarlet-kernelnext-llvm-toolchain-tryjob": {
+        "_template": "llvm_toolchain",
+        "boards": [
+            "scarlet-kernelnext"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "scarlet-kernelnext-payloads": {
+        "_template": "payloads",
+        "boards": [
+            "scarlet-kernelnext"
+        ]
+    },
+    "scarlet-kernelnext-payloads-tryjob": {
+        "_template": "payloads",
+        "boards": [
+            "scarlet-kernelnext"
+        ],
+        "debug": true,
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "scarlet-kernelnext-release": {
+        "_template": "release",
+        "boards": [
+            "scarlet-kernelnext"
+        ],
+        "important": false,
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"scarlet\",\n    \"name\": \"dru\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"scarlet\",\n    \"name\": \"druwl\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"scarlet\",\n    \"name\": \"dumo\",\n    \"test_suites\": []\n}"
+        ],
+        "vm_tests_override": null
+    },
+    "scarlet-kernelnext-release-tryjob": {
+        "_template": "release",
+        "boards": [
+            "scarlet-kernelnext"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests": [
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
+        ],
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"scarlet\",\n    \"name\": \"dru\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"scarlet\",\n    \"name\": \"druwl\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"scarlet\",\n    \"name\": \"dumo\",\n    \"test_suites\": []\n}"
+        ],
+        "paygen": false,
+        "push_image": false,
+        "suite_scheduling": false,
+        "vm_tests_override": null
+    },
+    "scarlet-kernelnext-unittest-stress": {
+        "_template": "unittest_stress",
+        "boards": [
+            "scarlet-kernelnext"
+        ],
+        "hw_tests_override": null,
+        "internal": true,
+        "luci_builder": "Try",
+        "manifest": "official.xml",
+        "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
+        "overlays": "both",
+        "useflags": [
+            "chrome_internal"
+        ]
+    },
     "scarlet-llvm-next-toolchain": {
         "_template": "llvm_next_toolchain",
         "boards": [
@@ -27175,7 +26455,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"scarlet\",\n    \"name\": \"druwl\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"scarlet\",\n    \"name\": \"dumo\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "scarlet-release-tryjob": {
@@ -27204,7 +26483,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "scarlet-unittest-stress": {
@@ -27311,8 +26589,6 @@
         "boards": [
             "senor"
         ],
-        "important": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "senor-release-tryjob": {
@@ -27336,7 +26612,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "senor-unittest-stress": {
@@ -27484,7 +26759,6 @@
             "sentry"
         ],
         "chrome_sdk_build_chrome": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "sentry-release-tryjob": {
@@ -27509,7 +26783,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "sentry-unittest-stress": {
@@ -27660,7 +26933,6 @@
         "hw_tests": [],
         "hw_tests_disabled_bug": "https://crbug.com/1092947",
         "hw_tests_override": [],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "setzer-release-tryjob": {
@@ -27678,7 +26950,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "setzer-unittest-stress": {
@@ -27793,7 +27064,6 @@
             "recovery",
             "factory"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "shadowkeep-release-tryjob": {
@@ -27814,7 +27084,6 @@
             "factory"
         ],
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "shadowkeep-unittest-stress": {
@@ -27832,6 +27101,556 @@
             "chrome_internal"
         ]
     },
+    "skolas-full": {
+        "_template": "full",
+        "boards": [
+            "skolas"
+        ],
+        "prebuilts": "public",
+        "run_cpeexport": true,
+        "useflags": [
+            "-chrome_internal"
+        ],
+        "vm_tests": []
+    },
+    "skolas-full-tryjob": {
+        "_template": "full",
+        "boards": [
+            "skolas"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests": [
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
+        ],
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "prebuilts": "public",
+        "run_cpeexport": true,
+        "useflags": [
+            "-chrome_internal"
+        ],
+        "vm_tests": []
+    },
+    "skolas-llvm-next-toolchain": {
+        "_template": "llvm_next_toolchain",
+        "boards": [
+            "skolas"
+        ]
+    },
+    "skolas-llvm-next-toolchain-tryjob": {
+        "_template": "llvm_next_toolchain",
+        "boards": [
+            "skolas"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "skolas-llvm-toolchain": {
+        "_template": "llvm_toolchain",
+        "boards": [
+            "skolas"
+        ]
+    },
+    "skolas-llvm-toolchain-tryjob": {
+        "_template": "llvm_toolchain",
+        "boards": [
+            "skolas"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "skolas-payloads": {
+        "_template": "payloads",
+        "boards": [
+            "skolas"
+        ]
+    },
+    "skolas-payloads-tryjob": {
+        "_template": "payloads",
+        "boards": [
+            "skolas"
+        ],
+        "debug": true,
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "skolas-release": {
+        "_template": "release",
+        "boards": [
+            "skolas"
+        ],
+        "hw_tests": [],
+        "hw_tests_disabled_bug": "b/209282476",
+        "hw_tests_override": [],
+        "important": false,
+        "sign_types": [
+            "recovery",
+            "factory"
+        ],
+        "vm_tests_override": null
+    },
+    "skolas-release-tryjob": {
+        "_template": "release",
+        "boards": [
+            "skolas"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests": [],
+        "hw_tests_disabled_bug": "b/209282476",
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "paygen": false,
+        "push_image": false,
+        "sign_types": [
+            "recovery",
+            "factory"
+        ],
+        "suite_scheduling": false,
+        "vm_tests_override": null
+    },
+    "skolas-unittest-stress": {
+        "_template": "unittest_stress",
+        "boards": [
+            "skolas"
+        ],
+        "hw_tests_override": null,
+        "internal": true,
+        "luci_builder": "Try",
+        "manifest": "official.xml",
+        "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
+        "overlays": "both",
+        "useflags": [
+            "chrome_internal"
+        ]
+    },
+    "skyrim-chausie-full": {
+        "_template": "full",
+        "boards": [
+            "skyrim-chausie"
+        ],
+        "prebuilts": "public",
+        "run_cpeexport": true,
+        "unittests": false,
+        "useflags": [
+            "-chrome_internal"
+        ],
+        "vm_tests": []
+    },
+    "skyrim-chausie-full-tryjob": {
+        "_template": "full",
+        "boards": [
+            "skyrim-chausie"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests": [
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
+        ],
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "prebuilts": "public",
+        "run_cpeexport": true,
+        "unittests": false,
+        "useflags": [
+            "-chrome_internal"
+        ],
+        "vm_tests": []
+    },
+    "skyrim-chausie-llvm-next-toolchain": {
+        "_template": "llvm_next_toolchain",
+        "boards": [
+            "skyrim-chausie"
+        ],
+        "unittests": false
+    },
+    "skyrim-chausie-llvm-next-toolchain-tryjob": {
+        "_template": "llvm_next_toolchain",
+        "boards": [
+            "skyrim-chausie"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "unittests": false
+    },
+    "skyrim-chausie-llvm-toolchain": {
+        "_template": "llvm_toolchain",
+        "boards": [
+            "skyrim-chausie"
+        ],
+        "unittests": false
+    },
+    "skyrim-chausie-llvm-toolchain-tryjob": {
+        "_template": "llvm_toolchain",
+        "boards": [
+            "skyrim-chausie"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "unittests": false
+    },
+    "skyrim-chausie-payloads": {
+        "_template": "payloads",
+        "boards": [
+            "skyrim-chausie"
+        ]
+    },
+    "skyrim-chausie-payloads-tryjob": {
+        "_template": "payloads",
+        "boards": [
+            "skyrim-chausie"
+        ],
+        "debug": true,
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "skyrim-chausie-release": {
+        "_template": "release",
+        "boards": [
+            "skyrim-chausie"
+        ],
+        "important": false,
+        "unittests": false,
+        "vm_tests_override": null
+    },
+    "skyrim-chausie-release-tryjob": {
+        "_template": "release",
+        "boards": [
+            "skyrim-chausie"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests": [
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
+        ],
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "paygen": false,
+        "push_image": false,
+        "suite_scheduling": false,
+        "unittests": false,
+        "vm_tests_override": null
+    },
+    "skyrim-chausie-unittest-stress": {
+        "_template": "unittest_stress",
+        "boards": [
+            "skyrim-chausie"
+        ],
+        "hw_tests_override": null,
+        "internal": true,
+        "luci_builder": "Try",
+        "manifest": "official.xml",
+        "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
+        "overlays": "both",
+        "useflags": [
+            "chrome_internal"
+        ]
+    },
+    "skyrim-full": {
+        "_template": "full",
+        "boards": [
+            "skyrim"
+        ],
+        "prebuilts": "public",
+        "run_cpeexport": true,
+        "unittests": false,
+        "useflags": [
+            "-chrome_internal"
+        ],
+        "vm_tests": []
+    },
+    "skyrim-full-tryjob": {
+        "_template": "full",
+        "boards": [
+            "skyrim"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests": [
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
+        ],
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "prebuilts": "public",
+        "run_cpeexport": true,
+        "unittests": false,
+        "useflags": [
+            "-chrome_internal"
+        ],
+        "vm_tests": []
+    },
+    "skyrim-kernelnext-full": {
+        "_template": "full",
+        "boards": [
+            "skyrim-kernelnext"
+        ],
+        "prebuilts": "public",
+        "run_cpeexport": true,
+        "unittests": false,
+        "useflags": [
+            "-chrome_internal"
+        ],
+        "vm_tests": []
+    },
+    "skyrim-kernelnext-full-tryjob": {
+        "_template": "full",
+        "boards": [
+            "skyrim-kernelnext"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests": [
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
+        ],
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "prebuilts": "public",
+        "run_cpeexport": true,
+        "unittests": false,
+        "useflags": [
+            "-chrome_internal"
+        ],
+        "vm_tests": []
+    },
+    "skyrim-kernelnext-llvm-next-toolchain": {
+        "_template": "llvm_next_toolchain",
+        "boards": [
+            "skyrim-kernelnext"
+        ],
+        "unittests": false
+    },
+    "skyrim-kernelnext-llvm-next-toolchain-tryjob": {
+        "_template": "llvm_next_toolchain",
+        "boards": [
+            "skyrim-kernelnext"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "unittests": false
+    },
+    "skyrim-kernelnext-llvm-toolchain": {
+        "_template": "llvm_toolchain",
+        "boards": [
+            "skyrim-kernelnext"
+        ],
+        "unittests": false
+    },
+    "skyrim-kernelnext-llvm-toolchain-tryjob": {
+        "_template": "llvm_toolchain",
+        "boards": [
+            "skyrim-kernelnext"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "unittests": false
+    },
+    "skyrim-kernelnext-payloads": {
+        "_template": "payloads",
+        "boards": [
+            "skyrim-kernelnext"
+        ]
+    },
+    "skyrim-kernelnext-payloads-tryjob": {
+        "_template": "payloads",
+        "boards": [
+            "skyrim-kernelnext"
+        ],
+        "debug": true,
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "skyrim-kernelnext-release": {
+        "_template": "release",
+        "boards": [
+            "skyrim-kernelnext"
+        ],
+        "chrome_sdk_build_chrome": false,
+        "important": false,
+        "unittests": false,
+        "vm_tests_override": null
+    },
+    "skyrim-kernelnext-release-tryjob": {
+        "_template": "release",
+        "boards": [
+            "skyrim-kernelnext"
+        ],
+        "chrome_sdk_build_chrome": false,
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests": [
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
+        ],
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "paygen": false,
+        "push_image": false,
+        "suite_scheduling": false,
+        "unittests": false,
+        "vm_tests_override": null
+    },
+    "skyrim-kernelnext-unittest-stress": {
+        "_template": "unittest_stress",
+        "boards": [
+            "skyrim-kernelnext"
+        ],
+        "hw_tests_override": null,
+        "internal": true,
+        "luci_builder": "Try",
+        "manifest": "official.xml",
+        "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
+        "overlays": "both",
+        "useflags": [
+            "chrome_internal"
+        ]
+    },
+    "skyrim-llvm-next-toolchain": {
+        "_template": "llvm_next_toolchain",
+        "boards": [
+            "skyrim"
+        ],
+        "unittests": false
+    },
+    "skyrim-llvm-next-toolchain-tryjob": {
+        "_template": "llvm_next_toolchain",
+        "boards": [
+            "skyrim"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "unittests": false
+    },
+    "skyrim-llvm-toolchain": {
+        "_template": "llvm_toolchain",
+        "boards": [
+            "skyrim"
+        ],
+        "unittests": false
+    },
+    "skyrim-llvm-toolchain-tryjob": {
+        "_template": "llvm_toolchain",
+        "boards": [
+            "skyrim"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "unittests": false
+    },
+    "skyrim-payloads": {
+        "_template": "payloads",
+        "boards": [
+            "skyrim"
+        ]
+    },
+    "skyrim-payloads-tryjob": {
+        "_template": "payloads",
+        "boards": [
+            "skyrim"
+        ],
+        "debug": true,
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "skyrim-release": {
+        "_template": "release",
+        "boards": [
+            "skyrim"
+        ],
+        "important": false,
+        "unittests": false,
+        "vm_tests_override": null
+    },
+    "skyrim-release-tryjob": {
+        "_template": "release",
+        "boards": [
+            "skyrim"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests": [
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
+        ],
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "paygen": false,
+        "push_image": false,
+        "suite_scheduling": false,
+        "unittests": false,
+        "vm_tests_override": null
+    },
+    "skyrim-unittest-stress": {
+        "_template": "unittest_stress",
+        "boards": [
+            "skyrim"
+        ],
+        "hw_tests_override": null,
+        "internal": true,
+        "luci_builder": "Try",
+        "manifest": "official.xml",
+        "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
+        "overlays": "both",
+        "useflags": [
+            "chrome_internal"
+        ]
+    },
     "sludge-full": {
         "_template": "full",
         "boards": [
@@ -28058,7 +27877,6 @@
         "upload_stripped_packages": [
             "sys-kernel/*kernel*"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "sludge-release-tryjob": {
@@ -28099,7 +27917,6 @@
         "upload_stripped_packages": [
             "sys-kernel/*kernel*"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "sludge-unittest-stress": {
@@ -28286,9 +28103,8 @@
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"snappy\",\n    \"name\": \"alan\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"snappy\",\n    \"name\": \"bigdaddy\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"snappy\",\n    \"name\": \"snappy\",\n    \"test_suites\": []\n}"
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"snappy\",\n    \"name\": \"snappy\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "snappy-kernelnext-release-tryjob": {
@@ -28312,12 +28128,11 @@
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"snappy\",\n    \"name\": \"alan\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"snappy\",\n    \"name\": \"bigdaddy\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"snappy\",\n    \"name\": \"snappy\",\n    \"test_suites\": []\n}"
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"snappy\",\n    \"name\": \"snappy\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "snappy-kernelnext-unittest-stress": {
@@ -28392,7 +28207,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"snappy\",\n    \"name\": \"bigdaddy\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"snappy\",\n    \"name\": \"snappy\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "snappy-release-tryjob": {
@@ -28421,7 +28235,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "snappy-unittest-stress": {
@@ -28589,7 +28402,6 @@
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"soraka\",\n    \"name\": \"soraka\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "soraka-libcamera-release-tryjob": {
@@ -28616,7 +28428,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "soraka-libcamera-unittest-stress": {
@@ -28689,7 +28500,6 @@
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"soraka\",\n    \"name\": \"soraka\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "soraka-release-tryjob": {
@@ -28716,7 +28526,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "soraka-unittest-stress": {
@@ -28811,6 +28620,149 @@
         ],
         "vm_tests": []
     },
+    "strongbad-kernelnext-full": {
+        "_template": "full",
+        "boards": [
+            "strongbad-kernelnext"
+        ],
+        "prebuilts": "public",
+        "run_cpeexport": true,
+        "useflags": [
+            "-chrome_internal"
+        ],
+        "vm_tests": []
+    },
+    "strongbad-kernelnext-full-tryjob": {
+        "_template": "full",
+        "boards": [
+            "strongbad-kernelnext"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests": [
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
+        ],
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "prebuilts": "public",
+        "run_cpeexport": true,
+        "useflags": [
+            "-chrome_internal"
+        ],
+        "vm_tests": []
+    },
+    "strongbad-kernelnext-llvm-next-toolchain": {
+        "_template": "llvm_next_toolchain",
+        "boards": [
+            "strongbad-kernelnext"
+        ]
+    },
+    "strongbad-kernelnext-llvm-next-toolchain-tryjob": {
+        "_template": "llvm_next_toolchain",
+        "boards": [
+            "strongbad-kernelnext"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "strongbad-kernelnext-llvm-toolchain": {
+        "_template": "llvm_toolchain",
+        "boards": [
+            "strongbad-kernelnext"
+        ]
+    },
+    "strongbad-kernelnext-llvm-toolchain-tryjob": {
+        "_template": "llvm_toolchain",
+        "boards": [
+            "strongbad-kernelnext"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "strongbad-kernelnext-payloads": {
+        "_template": "payloads",
+        "boards": [
+            "strongbad-kernelnext"
+        ]
+    },
+    "strongbad-kernelnext-payloads-tryjob": {
+        "_template": "payloads",
+        "boards": [
+            "strongbad-kernelnext"
+        ],
+        "debug": true,
+        "hw_tests_override": null,
+        "luci_builder": "Try"
+    },
+    "strongbad-kernelnext-release": {
+        "_template": "release",
+        "boards": [
+            "strongbad-kernelnext"
+        ],
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"strongbad\",\n    \"name\": \"coachz\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"strongbad\",\n    \"name\": \"homestar\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"strongbad\",\n    \"name\": \"mrbland\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"strongbad\",\n    \"name\": \"quackingstick\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"strongbad\",\n    \"name\": \"wormdingler\",\n    \"test_suites\": []\n}"
+        ],
+        "vm_tests_override": null
+    },
+    "strongbad-kernelnext-release-tryjob": {
+        "_template": "release",
+        "boards": [
+            "strongbad-kernelnext"
+        ],
+        "debug": true,
+        "display_label": "tryjob",
+        "hw_tests": [
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
+            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
+        ],
+        "hw_tests_override": null,
+        "luci_builder": "Try",
+        "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"strongbad\",\n    \"name\": \"coachz\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"strongbad\",\n    \"name\": \"homestar\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"strongbad\",\n    \"name\": \"mrbland\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"strongbad\",\n    \"name\": \"quackingstick\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"strongbad\",\n    \"name\": \"wormdingler\",\n    \"test_suites\": []\n}"
+        ],
+        "paygen": false,
+        "push_image": false,
+        "suite_scheduling": false,
+        "vm_tests_override": null
+    },
+    "strongbad-kernelnext-unittest-stress": {
+        "_template": "unittest_stress",
+        "boards": [
+            "strongbad-kernelnext"
+        ],
+        "hw_tests_override": null,
+        "internal": true,
+        "luci_builder": "Try",
+        "manifest": "official.xml",
+        "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
+        "overlays": "both",
+        "useflags": [
+            "chrome_internal"
+        ]
+    },
     "strongbad-llvm-next-toolchain": {
         "_template": "llvm_next_toolchain",
         "boards": [
@@ -28866,14 +28818,14 @@
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"strongbad\",\n    \"name\": \"coachz\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"strongbad\",\n    \"name\": \"homestar\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"strongbad\",\n    \"name\": \"mrbland\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"strongbad\",\n    \"name\": \"wormdingler\",\n    \"test_suites\": []\n}"
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"strongbad\",\n    \"name\": \"mrbland\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"strongbad\",\n    \"name\": \"quackingstick\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"strongbad\",\n    \"name\": \"wormdingler\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
         "sign_types": [
             "recovery",
             "factory"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "strongbad-release-tryjob": {
@@ -28897,8 +28849,9 @@
         "models": [
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"strongbad\",\n    \"name\": \"coachz\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"strongbad\",\n    \"name\": \"homestar\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"strongbad\",\n    \"name\": \"mrbland\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"strongbad\",\n    \"name\": \"wormdingler\",\n    \"test_suites\": []\n}"
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"strongbad\",\n    \"name\": \"mrbland\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"strongbad\",\n    \"name\": \"quackingstick\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"strongbad\",\n    \"name\": \"wormdingler\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
         "paygen": false,
         "push_image": false,
@@ -28907,7 +28860,6 @@
             "factory"
         ],
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "strongbad-unittest-stress": {
@@ -29263,7 +29215,6 @@
         "upload_stripped_packages": [
             "sys-kernel/*kernel*"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "tael-release-tryjob": {
@@ -29305,7 +29256,6 @@
         "upload_stripped_packages": [
             "sys-kernel/*kernel*"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "tael-unittest-stress": {
@@ -29574,7 +29524,6 @@
         "upload_stripped_packages": [
             "sys-kernel/*kernel*"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "tatl-release-tryjob": {
@@ -29616,7 +29565,6 @@
         "upload_stripped_packages": [
             "sys-kernel/*kernel*"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "tatl-unittest-stress": {
@@ -29784,7 +29732,6 @@
         ],
         "chrome_sdk_build_chrome": false,
         "enable_skylab_cts_hw_tests": true,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "terra-release-tryjob": {
@@ -29810,7 +29757,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "terra-unittest-stress": {
@@ -30022,13 +29968,13 @@
         ],
         "important": false,
         "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"kingoftown\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"lazor\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"limozeen\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"pazquel\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"pompom\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"trogdor\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "trogdor-arc-r-release-tryjob": {
@@ -30050,6 +29996,7 @@
         "hw_tests_override": null,
         "luci_builder": "Try",
         "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"kingoftown\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"lazor\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"limozeen\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"pazquel\",\n    \"test_suites\": []\n}",
@@ -30059,7 +30006,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "trogdor-arc-r-unittest-stress": {
@@ -30168,13 +30114,13 @@
         ],
         "important": false,
         "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"kingoftown\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"lazor\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"limozeen\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"pazquel\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"pompom\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"trogdor\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "trogdor-connectivitynext-release-tryjob": {
@@ -30196,6 +30142,7 @@
         "hw_tests_override": null,
         "luci_builder": "Try",
         "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"kingoftown\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"lazor\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"limozeen\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"pazquel\",\n    \"test_suites\": []\n}",
@@ -30205,7 +30152,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "trogdor-connectivitynext-unittest-stress": {
@@ -30389,15 +30335,14 @@
         "boards": [
             "trogdor-kernelnext"
         ],
-        "important": false,
         "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"kingoftown\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"lazor\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"limozeen\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"limozeen\",\n    \"test_suites\": [\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"pazquel\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"pompom\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"pompom\",\n    \"test_suites\": [\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"trogdor\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "trogdor-kernelnext-release-tryjob": {
@@ -30419,16 +30364,16 @@
         "hw_tests_override": null,
         "luci_builder": "Try",
         "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"kingoftown\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"lazor\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"limozeen\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"limozeen\",\n    \"test_suites\": [\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"pazquel\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"pompom\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"pompom\",\n    \"test_suites\": [\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"trogdor\",\n    \"test_suites\": []\n}"
         ],
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "trogdor-kernelnext-unittest-stress": {
@@ -30498,10 +30443,12 @@
         "boards": [
             "trogdor"
         ],
+        "important": false,
         "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"kingoftown\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"lazor\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"limozeen\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"pazquel\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"pazquel\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"pompom\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"trogdor\",\n    \"test_suites\": []\n}"
         ],
@@ -30509,7 +30456,6 @@
             "recovery",
             "factory"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "trogdor-release-tryjob": {
@@ -30531,9 +30477,10 @@
         "hw_tests_override": null,
         "luci_builder": "Try",
         "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"kingoftown\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"lazor\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"limozeen\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"pazquel\",\n    \"test_suites\": []\n}",
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"pazquel\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"pompom\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"trogdor\",\n    \"test_suites\": []\n}"
         ],
@@ -30544,7 +30491,6 @@
             "factory"
         ],
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "trogdor-unittest-stress": {
@@ -30656,7 +30602,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor-zephyr\",\n    \"name\": \"lazor\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor-zephyr\",\n    \"name\": \"limozeen\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "trogdor-zephyr-release-tryjob": {
@@ -30684,7 +30629,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "trogdor-zephyr-unittest-stress": {
@@ -30793,6 +30737,7 @@
         ],
         "important": false,
         "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"kingoftown\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"lazor\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"limozeen\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"pazquel\",\n    \"test_suites\": []\n}",
@@ -30803,7 +30748,6 @@
             "recovery",
             "factory"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "trogdor64-release-tryjob": {
@@ -30825,6 +30769,7 @@
         "hw_tests_override": null,
         "luci_builder": "Try",
         "models": [
+            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"kingoftown\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"lazor\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"au\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"limozeen\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"trogdor\",\n    \"name\": \"pazquel\",\n    \"test_suites\": []\n}",
@@ -30838,7 +30783,6 @@
             "factory"
         ],
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "trogdor64-unittest-stress": {
@@ -30986,7 +30930,6 @@
             "ultima"
         ],
         "chrome_sdk_build_chrome": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "ultima-release-tryjob": {
@@ -31011,7 +30954,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "ultima-unittest-stress": {
@@ -31069,139 +31011,6 @@
         "suite_scheduling": false,
         "workspace_branch": "factory-veyron-7505.B"
     },
-    "veyron_fievel-full": {
-        "_template": "full",
-        "boards": [
-            "veyron_fievel"
-        ],
-        "prebuilts": "public",
-        "run_cpeexport": true,
-        "useflags": [
-            "-chrome_internal"
-        ],
-        "vm_tests": []
-    },
-    "veyron_fievel-full-tryjob": {
-        "_template": "full",
-        "boards": [
-            "veyron_fievel"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "prebuilts": "public",
-        "run_cpeexport": true,
-        "useflags": [
-            "-chrome_internal"
-        ],
-        "vm_tests": []
-    },
-    "veyron_fievel-llvm-next-toolchain": {
-        "_template": "llvm_next_toolchain",
-        "boards": [
-            "veyron_fievel"
-        ]
-    },
-    "veyron_fievel-llvm-next-toolchain-tryjob": {
-        "_template": "llvm_next_toolchain",
-        "boards": [
-            "veyron_fievel"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests_override": null,
-        "luci_builder": "Try"
-    },
-    "veyron_fievel-llvm-toolchain": {
-        "_template": "llvm_toolchain",
-        "boards": [
-            "veyron_fievel"
-        ]
-    },
-    "veyron_fievel-llvm-toolchain-tryjob": {
-        "_template": "llvm_toolchain",
-        "boards": [
-            "veyron_fievel"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests_override": null,
-        "luci_builder": "Try"
-    },
-    "veyron_fievel-payloads": {
-        "_template": "payloads",
-        "boards": [
-            "veyron_fievel"
-        ]
-    },
-    "veyron_fievel-payloads-tryjob": {
-        "_template": "payloads",
-        "boards": [
-            "veyron_fievel"
-        ],
-        "debug": true,
-        "hw_tests_override": null,
-        "luci_builder": "Try"
-    },
-    "veyron_fievel-release": {
-        "_template": "release",
-        "boards": [
-            "veyron_fievel"
-        ],
-        "chrome_sdk_build_chrome": false,
-        "vm_tests": [],
-        "vm_tests_override": null
-    },
-    "veyron_fievel-release-tryjob": {
-        "_template": "release",
-        "boards": [
-            "veyron_fievel"
-        ],
-        "chrome_sdk_build_chrome": false,
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "paygen": false,
-        "push_image": false,
-        "suite_scheduling": false,
-        "vm_tests": [],
-        "vm_tests_override": null
-    },
-    "veyron_fievel-unittest-stress": {
-        "_template": "unittest_stress",
-        "boards": [
-            "veyron_fievel"
-        ],
-        "hw_tests_override": null,
-        "internal": true,
-        "luci_builder": "Try",
-        "manifest": "official.xml",
-        "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
-        "overlays": "both",
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
     "veyron_mighty-full": {
         "_template": "full",
         "boards": [
@@ -31291,7 +31100,6 @@
         "boards": [
             "veyron_mighty"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "veyron_mighty-release-tryjob": {
@@ -31315,7 +31123,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "veyron_mighty-unittest-stress": {
@@ -31422,7 +31229,6 @@
         "boards": [
             "veyron_minnie"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "veyron_minnie-release-tryjob": {
@@ -31446,7 +31252,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "veyron_minnie-unittest-stress": {
@@ -31464,175 +31269,6 @@
             "chrome_internal"
         ]
     },
-    "veyron_rialto-factory-veyron-7505.B-factorybranch": {
-        "_template": "factorybranch",
-        "boards": [
-            "veyron_rialto"
-        ],
-        "packages": [
-            "virtual/target-os",
-            "virtual/target-os-dev",
-            "virtual/target-os-test",
-            "chromeos-base/chromeos-installshim",
-            "chromeos-base/chromeos-factory",
-            "chromeos-base/chromeos-hwid",
-            "chromeos-base/autotest-factory-install",
-            "chromeos-base/autotest-all"
-        ],
-        "workspace_branch": "factory-veyron-7505.B"
-    },
-    "veyron_rialto-factory-veyron-7505.B-factorybranch-tryjob": {
-        "_template": "factorybranch",
-        "boards": [
-            "veyron_rialto"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "packages": [
-            "virtual/target-os",
-            "virtual/target-os-dev",
-            "virtual/target-os-test",
-            "chromeos-base/chromeos-installshim",
-            "chromeos-base/chromeos-factory",
-            "chromeos-base/chromeos-hwid",
-            "chromeos-base/autotest-factory-install",
-            "chromeos-base/autotest-all"
-        ],
-        "push_image": false,
-        "suite_scheduling": false,
-        "workspace_branch": "factory-veyron-7505.B"
-    },
-    "veyron_rialto-full": {
-        "_template": "full",
-        "boards": [
-            "veyron_rialto"
-        ],
-        "prebuilts": "public",
-        "run_cpeexport": true,
-        "useflags": [
-            "-chrome_internal"
-        ],
-        "vm_tests": []
-    },
-    "veyron_rialto-full-tryjob": {
-        "_template": "full",
-        "boards": [
-            "veyron_rialto"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "prebuilts": "public",
-        "run_cpeexport": true,
-        "useflags": [
-            "-chrome_internal"
-        ],
-        "vm_tests": []
-    },
-    "veyron_rialto-llvm-next-toolchain": {
-        "_template": "llvm_next_toolchain",
-        "boards": [
-            "veyron_rialto"
-        ]
-    },
-    "veyron_rialto-llvm-next-toolchain-tryjob": {
-        "_template": "llvm_next_toolchain",
-        "boards": [
-            "veyron_rialto"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests_override": null,
-        "luci_builder": "Try"
-    },
-    "veyron_rialto-llvm-toolchain": {
-        "_template": "llvm_toolchain",
-        "boards": [
-            "veyron_rialto"
-        ]
-    },
-    "veyron_rialto-llvm-toolchain-tryjob": {
-        "_template": "llvm_toolchain",
-        "boards": [
-            "veyron_rialto"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests_override": null,
-        "luci_builder": "Try"
-    },
-    "veyron_rialto-payloads": {
-        "_template": "payloads",
-        "boards": [
-            "veyron_rialto"
-        ]
-    },
-    "veyron_rialto-payloads-tryjob": {
-        "_template": "payloads",
-        "boards": [
-            "veyron_rialto"
-        ],
-        "debug": true,
-        "hw_tests_override": null,
-        "luci_builder": "Try"
-    },
-    "veyron_rialto-release": {
-        "_template": "release",
-        "boards": [
-            "veyron_rialto"
-        ],
-        "chrome_sdk_build_chrome": false,
-        "hw_tests": [],
-        "hw_tests_disabled_bug": "https://b/141387161",
-        "hw_tests_override": [],
-        "vm_tests": [],
-        "vm_tests_override": null
-    },
-    "veyron_rialto-release-tryjob": {
-        "_template": "release",
-        "boards": [
-            "veyron_rialto"
-        ],
-        "chrome_sdk_build_chrome": false,
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests": [],
-        "hw_tests_disabled_bug": "https://b/141387161",
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "paygen": false,
-        "push_image": false,
-        "suite_scheduling": false,
-        "vm_tests": [],
-        "vm_tests_override": null
-    },
-    "veyron_rialto-unittest-stress": {
-        "_template": "unittest_stress",
-        "boards": [
-            "veyron_rialto"
-        ],
-        "hw_tests_override": null,
-        "internal": true,
-        "luci_builder": "Try",
-        "manifest": "official.xml",
-        "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
-        "overlays": "both",
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
     "veyron_speedy-full": {
         "_template": "full",
         "boards": [
@@ -31722,7 +31358,6 @@
         "boards": [
             "veyron_speedy"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "veyron_speedy-release-tryjob": {
@@ -31746,7 +31381,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "veyron_speedy-unittest-stress": {
@@ -31804,139 +31438,6 @@
         "suite_scheduling": false,
         "workspace_branch": "factory-veyron-7505.B"
     },
-    "veyron_tiger-full": {
-        "_template": "full",
-        "boards": [
-            "veyron_tiger"
-        ],
-        "prebuilts": "public",
-        "run_cpeexport": true,
-        "useflags": [
-            "-chrome_internal"
-        ],
-        "vm_tests": []
-    },
-    "veyron_tiger-full-tryjob": {
-        "_template": "full",
-        "boards": [
-            "veyron_tiger"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "prebuilts": "public",
-        "run_cpeexport": true,
-        "useflags": [
-            "-chrome_internal"
-        ],
-        "vm_tests": []
-    },
-    "veyron_tiger-llvm-next-toolchain": {
-        "_template": "llvm_next_toolchain",
-        "boards": [
-            "veyron_tiger"
-        ]
-    },
-    "veyron_tiger-llvm-next-toolchain-tryjob": {
-        "_template": "llvm_next_toolchain",
-        "boards": [
-            "veyron_tiger"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests_override": null,
-        "luci_builder": "Try"
-    },
-    "veyron_tiger-llvm-toolchain": {
-        "_template": "llvm_toolchain",
-        "boards": [
-            "veyron_tiger"
-        ]
-    },
-    "veyron_tiger-llvm-toolchain-tryjob": {
-        "_template": "llvm_toolchain",
-        "boards": [
-            "veyron_tiger"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests_override": null,
-        "luci_builder": "Try"
-    },
-    "veyron_tiger-payloads": {
-        "_template": "payloads",
-        "boards": [
-            "veyron_tiger"
-        ]
-    },
-    "veyron_tiger-payloads-tryjob": {
-        "_template": "payloads",
-        "boards": [
-            "veyron_tiger"
-        ],
-        "debug": true,
-        "hw_tests_override": null,
-        "luci_builder": "Try"
-    },
-    "veyron_tiger-release": {
-        "_template": "release",
-        "boards": [
-            "veyron_tiger"
-        ],
-        "chrome_sdk_build_chrome": false,
-        "vm_tests": [],
-        "vm_tests_override": null
-    },
-    "veyron_tiger-release-tryjob": {
-        "_template": "release",
-        "boards": [
-            "veyron_tiger"
-        ],
-        "chrome_sdk_build_chrome": false,
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "paygen": false,
-        "push_image": false,
-        "suite_scheduling": false,
-        "vm_tests": [],
-        "vm_tests_override": null
-    },
-    "veyron_tiger-unittest-stress": {
-        "_template": "unittest_stress",
-        "boards": [
-            "veyron_tiger"
-        ],
-        "hw_tests_override": null,
-        "internal": true,
-        "luci_builder": "Try",
-        "manifest": "official.xml",
-        "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
-        "overlays": "both",
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
     "viking-full": {
         "_template": "full",
         "boards": [
@@ -32232,7 +31733,6 @@
         "suite_scheduling": false,
         "sync_chrome": false,
         "upload_hw_test_artifacts": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "viking-poc2-release": {
@@ -32257,7 +31757,6 @@
         "signer_tests": false,
         "sync_chrome": false,
         "upload_hw_test_artifacts": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "viking-poc2-release-tryjob": {
@@ -32287,7 +31786,6 @@
         "suite_scheduling": false,
         "sync_chrome": false,
         "upload_hw_test_artifacts": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "viking-poc2-unittest-stress": {
@@ -32339,7 +31837,6 @@
         "suite_scheduling": false,
         "sync_chrome": false,
         "upload_hw_test_artifacts": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "viking-release": {
@@ -32364,7 +31861,6 @@
         "signer_tests": false,
         "sync_chrome": false,
         "upload_hw_test_artifacts": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "viking-release-tryjob": {
@@ -32394,7 +31890,6 @@
         "suite_scheduling": false,
         "sync_chrome": false,
         "upload_hw_test_artifacts": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "viking-unittest-stress": {
@@ -32541,7 +32036,6 @@
         "notification_configs": [
             "{\n    \"email\": \"borealis-release-builder-alerts@google.com\",\n    \"template\": \"legacy_release\",\n    \"threshold\": 2\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "volteer-borealis-release-tryjob": {
@@ -32587,7 +32081,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "volteer-borealis-unittest-stress": {
@@ -32778,7 +32271,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"volteer\",\n    \"name\": \"volteer_tcpmv1\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"volteer\",\n    \"name\": \"voxel\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "volteer-kernelnext-release-tryjob": {
@@ -32828,7 +32320,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "volteer-kernelnext-unittest-stress": {
@@ -32990,7 +32481,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"volteer\",\n    \"name\": \"volteer2\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"volteer\",\n    \"name\": \"voxel\",\n    \"test_suites\": [\n        \"sanity\",\n        \"bvt-inline\",\n        \"bvt-tast-cq\",\n        \"bvt-installer\",\n        \"bvt-arc\",\n        \"bvt-cq\",\n        \"bvt-perbuild\",\n        \"bvt-tast-informational\"\n    ]\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "volteer-manatee-release-tryjob": {
@@ -33036,7 +32526,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "volteer-manatee-unittest-stress": {
@@ -33104,7 +32593,6 @@
             "recovery",
             "factory"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "volteer-release-tryjob": {
@@ -33158,7 +32646,6 @@
             "factory"
         ],
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "volteer-unittest-stress": {
@@ -33176,148 +32663,6 @@
             "chrome_internal"
         ]
     },
-    "volteer-zephyr-full": {
-        "_template": "full",
-        "boards": [
-            "volteer-zephyr"
-        ],
-        "prebuilts": "public",
-        "run_cpeexport": true,
-        "useflags": [
-            "-chrome_internal"
-        ],
-        "vm_tests": []
-    },
-    "volteer-zephyr-full-tryjob": {
-        "_template": "full",
-        "boards": [
-            "volteer-zephyr"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "prebuilts": "public",
-        "run_cpeexport": true,
-        "useflags": [
-            "-chrome_internal"
-        ],
-        "vm_tests": []
-    },
-    "volteer-zephyr-llvm-next-toolchain": {
-        "_template": "llvm_next_toolchain",
-        "boards": [
-            "volteer-zephyr"
-        ]
-    },
-    "volteer-zephyr-llvm-next-toolchain-tryjob": {
-        "_template": "llvm_next_toolchain",
-        "boards": [
-            "volteer-zephyr"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests_override": null,
-        "luci_builder": "Try"
-    },
-    "volteer-zephyr-llvm-toolchain": {
-        "_template": "llvm_toolchain",
-        "boards": [
-            "volteer-zephyr"
-        ]
-    },
-    "volteer-zephyr-llvm-toolchain-tryjob": {
-        "_template": "llvm_toolchain",
-        "boards": [
-            "volteer-zephyr"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests_override": null,
-        "luci_builder": "Try"
-    },
-    "volteer-zephyr-payloads": {
-        "_template": "payloads",
-        "boards": [
-            "volteer-zephyr"
-        ]
-    },
-    "volteer-zephyr-payloads-tryjob": {
-        "_template": "payloads",
-        "boards": [
-            "volteer-zephyr"
-        ],
-        "debug": true,
-        "hw_tests_override": null,
-        "luci_builder": "Try"
-    },
-    "volteer-zephyr-release": {
-        "_template": "release",
-        "boards": [
-            "volteer-zephyr"
-        ],
-        "important": false,
-        "models": [
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"volteer-zephyr\",\n    \"name\": \"delbin\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"volteer-zephyr\",\n    \"name\": \"volteer2\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"volteer-zephyr\",\n    \"name\": \"volteer2_ti50\",\n    \"test_suites\": []\n}"
-        ],
-        "vm_tests": [],
-        "vm_tests_override": null
-    },
-    "volteer-zephyr-release-tryjob": {
-        "_template": "release",
-        "boards": [
-            "volteer-zephyr"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "models": [
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"volteer-zephyr\",\n    \"name\": \"delbin\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"volteer-zephyr\",\n    \"name\": \"volteer2\",\n    \"test_suites\": []\n}",
-            "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"volteer-zephyr\",\n    \"name\": \"volteer2_ti50\",\n    \"test_suites\": []\n}"
-        ],
-        "paygen": false,
-        "push_image": false,
-        "suite_scheduling": false,
-        "vm_tests": [],
-        "vm_tests_override": null
-    },
-    "volteer-zephyr-unittest-stress": {
-        "_template": "unittest_stress",
-        "boards": [
-            "volteer-zephyr"
-        ],
-        "hw_tests_override": null,
-        "internal": true,
-        "luci_builder": "Try",
-        "manifest": "official.xml",
-        "manifest_repo_url": "https://chrome-internal-review.googlesource.com/chromeos/manifest-internal",
-        "overlays": "both",
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
     "whirlwind-full": {
         "_template": "full",
         "boards": [
@@ -33443,7 +32788,6 @@
         "hw_tests_override": [],
         "paygen_skip_testing": true,
         "sync_chrome": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "whirlwind-release-tryjob": {
@@ -33463,7 +32807,6 @@
         "push_image": false,
         "suite_scheduling": false,
         "sync_chrome": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "whirlwind-test-ap": {
@@ -33677,7 +33020,6 @@
             "wizpig"
         ],
         "chrome_sdk_build_chrome": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "wizpig-release-tryjob": {
@@ -33702,7 +33044,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "wizpig-unittest-stress": {
@@ -33888,7 +33229,6 @@
         "suite_scheduling": false,
         "sync_chrome": false,
         "upload_hw_test_artifacts": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "wristpin-release": {
@@ -33914,7 +33254,6 @@
         "signer_tests": false,
         "sync_chrome": false,
         "upload_hw_test_artifacts": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "wristpin-release-tryjob": {
@@ -33945,7 +33284,6 @@
         "suite_scheduling": false,
         "sync_chrome": false,
         "upload_hw_test_artifacts": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "wristpin-unittest-stress": {
@@ -34008,37 +33346,6 @@
         "usepkg_toolchain": false,
         "vm_tests": []
     },
-    "x32-generic-incremental": {
-        "_template": "incremental",
-        "boards": [
-            "x32-generic"
-        ],
-        "usepkg_toolchain": false,
-        "vm_tests": []
-    },
-    "x32-generic-incremental-tryjob": {
-        "_template": "incremental",
-        "boards": [
-            "x32-generic"
-        ],
-        "chroot_replace": true,
-        "debug": true,
-        "display_label": "tryjob",
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-inline\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-arc\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 0,\n    \"timeout\": 10800,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-informational\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-installer\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-cq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": true,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 0,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PostBuild\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-perbuild\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 15000,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": null,
-        "luci_builder": "Try",
-        "uprev": true,
-        "usepkg_toolchain": false,
-        "vm_tests": []
-    },
     "x32-generic-llvm-next-toolchain": {
         "_template": "llvm_next_toolchain",
         "boards": [
@@ -34197,7 +33504,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"zork\",\n    \"name\": \"woomax\",\n    \"test_suites\": []\n}"
         ],
         "unittests": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "zork-arc-r-release-tryjob": {
@@ -34238,7 +33544,6 @@
         "push_image": false,
         "suite_scheduling": false,
         "unittests": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "zork-arc-r-unittest-stress": {
@@ -34256,46 +33561,6 @@
             "chrome_internal"
         ]
     },
-    "zork-arc-r-vmrvc-android-pfq": {
-        "_template": "vmrvc_android_pfq",
-        "boards": [
-            "zork-arc-r"
-        ],
-        "enable_skylab_hw_tests": true,
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": true,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": true,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"Build\",\n    \"quota_account\": \"pfq\",\n    \"retry\": true,\n    \"suite\": \"sanity\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": true,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"PFQ\",\n    \"quota_account\": \"pfq\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-android-pfq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}"
-        ],
-        "hw_tests_override": [
-            "{\n    \"async\": false,\n    \"blocking\": true,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"DEFAULT\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"sanity\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"DEFAULT\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-android-pfq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}"
-        ],
-        "manifest": "official.xml",
-        "unittests": false,
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
-    "zork-arc-r-vmrvc-android-pfq-tryjob": {
-        "_template": "vmrvc_android_pfq",
-        "boards": [
-            "zork-arc-r"
-        ],
-        "debug": true,
-        "display_label": "tryjob",
-        "enable_skylab_hw_tests": true,
-        "hw_tests": [
-            "{\n    \"async\": false,\n    \"blocking\": true,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"DEFAULT\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"sanity\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}",
-            "{\n    \"async\": false,\n    \"blocking\": false,\n    \"critical\": false,\n    \"enable_skylab\": true,\n    \"file_bugs\": false,\n    \"max_retries\": 5,\n    \"minimum_duts\": 1,\n    \"offload_failures_only\": false,\n    \"pool\": \"quota\",\n    \"priority\": \"DEFAULT\",\n    \"quota_account\": \"legacypool-suites\",\n    \"retry\": true,\n    \"suite\": \"bvt-tast-android-pfq\",\n    \"suite_args\": null,\n    \"suite_min_duts\": 1,\n    \"timeout\": 21600,\n    \"warn_only\": false\n}"
-        ],
-        "luci_builder": "Try",
-        "manifest": "official.xml",
-        "unittests": false,
-        "uprev": true,
-        "useflags": [
-            "chrome_internal"
-        ]
-    },
     "zork-borealis-full": {
         "_template": "full",
         "boards": [
@@ -34421,7 +33686,6 @@
             "{\n    \"email\": \"borealis-release-builder-alerts@google.com\",\n    \"template\": \"legacy_release\",\n    \"threshold\": 2\n}"
         ],
         "unittests": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "zork-borealis-release-tryjob": {
@@ -34462,7 +33726,6 @@
         "push_image": false,
         "suite_scheduling": false,
         "unittests": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "zork-borealis-unittest-stress": {
@@ -34587,7 +33850,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"zork\",\n    \"name\": \"woomax\",\n    \"test_suites\": []\n}"
         ],
         "unittests": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "zork-connectivitynext-release-tryjob": {
@@ -34628,7 +33890,6 @@
         "push_image": false,
         "suite_scheduling": false,
         "unittests": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "zork-connectivitynext-unittest-stress": {
@@ -34792,7 +34053,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"zork-floss\",\n    \"name\": \"vilboz360\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"zork-floss\",\n    \"name\": \"woomax\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "zork-floss-release-tryjob": {
@@ -34832,7 +34092,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "zork-floss-unittest-stress": {
@@ -34855,6 +34114,7 @@
         "boards": [
             "zork"
         ],
+        "manifest_version": true,
         "prebuilts": "public",
         "run_cpeexport": true,
         "unittests": false,
@@ -34881,6 +34141,7 @@
         ],
         "hw_tests_override": null,
         "luci_builder": "Try",
+        "manifest_version": true,
         "prebuilts": "public",
         "run_cpeexport": true,
         "unittests": false,
@@ -34995,7 +34256,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"zork\",\n    \"name\": \"vilboz360\",\n    \"test_suites\": []\n}",
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"zork\",\n    \"name\": \"woomax\",\n    \"test_suites\": []\n}"
         ],
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "zork-kernelnext-release-tryjob": {
@@ -35035,7 +34295,6 @@
         "paygen": false,
         "push_image": false,
         "suite_scheduling": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "zork-kernelnext-unittest-stress": {
@@ -35196,7 +34455,6 @@
             "{\n    \"enable_skylab\": true,\n    \"lab_board_name\": \"zork-minios\",\n    \"name\": \"woomax\",\n    \"test_suites\": []\n}"
         ],
         "unittests": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "zork-minios-release-tryjob": {
@@ -35237,7 +34495,6 @@
         "push_image": false,
         "suite_scheduling": false,
         "unittests": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "zork-minios-unittest-stress": {
@@ -35297,7 +34554,6 @@
             "accessory_rwsig"
         ],
         "unittests": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "zork-release-tryjob": {
@@ -35343,7 +34599,6 @@
         ],
         "suite_scheduling": false,
         "unittests": false,
-        "vm_tests": [],
         "vm_tests_override": null
     },
     "zork-unittest-stress": {
diff --git a/config/ge_build_config.json b/config/ge_build_config.json
index 73014f1..dc09b07 100644
--- a/config/ge_build_config.json
+++ b/config/ge_build_config.json
@@ -38,18 +38,6 @@
       ]
     },
     {
-      "name": "beaglebone_servo",
-      "configs": [
-        {
-          "builder": "RELEASE",
-          "experimental": false,
-          "leader_board": false,
-          "board_group": "",
-          "arch": "UNKNOWN"
-        }
-      ]
-    },
-    {
       "name": "betty",
       "configs": [
         {
@@ -122,35 +110,11 @@
       ]
     },
     {
-      "name": "bob",
-      "configs": [
-        {
-          "builder": "RELEASE",
-          "experimental": false,
-          "leader_board": false,
-          "board_group": "gru",
-          "arch": "ARM_INTERNAL"
-        }
-      ]
-    },
-    {
-      "name": "brask",
-      "configs": [
-        {
-          "builder": "RELEASE",
-          "experimental": true,
-          "leader_board": false,
-          "board_group": "",
-          "arch": "X86_INTERNAL"
-        }
-      ]
-    },
-    {
       "name": "bubs",
       "configs": [
         {
           "builder": "RELEASE",
-          "experimental": true,
+          "experimental": false,
           "leader_board": true,
           "board_group": "",
           "arch": "ARM_INTERNAL"
@@ -182,18 +146,6 @@
       ]
     },
     {
-      "name": "caroline-kernelnext",
-      "configs": [
-        {
-          "builder": "RELEASE",
-          "experimental": true,
-          "leader_board": false,
-          "board_group": "glados",
-          "arch": "X86_INTERNAL"
-        }
-      ]
-    },
-    {
       "name": "caroline-ndktranslation",
       "configs": [
         {
@@ -218,18 +170,6 @@
       ]
     },
     {
-      "name": "cave",
-      "configs": [
-        {
-          "builder": "RELEASE",
-          "experimental": false,
-          "leader_board": false,
-          "board_group": "glados",
-          "arch": "X86_INTERNAL"
-        }
-      ]
-    },
-    {
       "name": "celes",
       "configs": [
         {
@@ -254,14 +194,14 @@
       ]
     },
     {
-      "name": "coral-kernelnext",
+      "name": "corsola",
       "configs": [
         {
           "builder": "RELEASE",
-          "experimental": true,
-          "leader_board": false,
-          "board_group": "",
-          "arch": "X86_INTERNAL"
+          "experimental": false,
+          "leader_board": true,
+          "board_group": "corsola",
+          "arch": "ARM_INTERNAL"
         }
       ]
     },
@@ -290,18 +230,6 @@
       ]
     },
     {
-      "name": "gale",
-      "configs": [
-        {
-          "builder": "RELEASE",
-          "experimental": false,
-          "leader_board": true,
-          "board_group": "gale",
-          "arch": "UNKNOWN"
-        }
-      ]
-    },
-    {
       "name": "goroh",
       "configs": [
         {
@@ -338,6 +266,18 @@
       ]
     },
     {
+      "name": "guybrush-kernelnext",
+      "configs": [
+        {
+          "builder": "RELEASE",
+          "experimental": true,
+          "leader_board": false,
+          "board_group": "guybrush",
+          "arch": "UNKNOWN"
+        }
+      ]
+    },
+    {
       "name": "hana",
       "configs": [
         {
@@ -398,54 +338,6 @@
       ]
     },
     {
-      "name": "kevin",
-      "configs": [
-        {
-          "builder": "RELEASE",
-          "experimental": false,
-          "leader_board": false,
-          "board_group": "gru",
-          "arch": "ARM_INTERNAL"
-        }
-      ]
-    },
-    {
-      "name": "kevin-kernelnext",
-      "configs": [
-        {
-          "builder": "RELEASE",
-          "experimental": false,
-          "leader_board": false,
-          "board_group": "",
-          "arch": "ARM_INTERNAL"
-        }
-      ]
-    },
-    {
-      "name": "kevin-userdebug",
-      "configs": [
-        {
-          "builder": "RELEASE",
-          "experimental": true,
-          "leader_board": false,
-          "board_group": "",
-          "arch": "ARM_INTERNAL"
-        }
-      ]
-    },
-    {
-      "name": "kevin64",
-      "configs": [
-        {
-          "builder": "RELEASE",
-          "experimental": true,
-          "leader_board": false,
-          "board_group": "gru",
-          "arch": "ARM_INTERNAL"
-        }
-      ]
-    },
-    {
       "name": "lars",
       "configs": [
         {
@@ -482,18 +374,6 @@
       ]
     },
     {
-      "name": "mistral",
-      "configs": [
-        {
-          "builder": "RELEASE",
-          "experimental": true,
-          "leader_board": false,
-          "board_group": "",
-          "arch": "ARM_INTERNAL"
-        }
-      ]
-    },
-    {
       "name": "nissa",
       "configs": [
         {
@@ -594,7 +474,7 @@
       "configs": [
         {
           "builder": "RELEASE",
-          "experimental": true,
+          "experimental": false,
           "leader_board": true,
           "board_group": "",
           "arch": "ARM_INTERNAL"
@@ -638,6 +518,54 @@
       ]
     },
     {
+      "name": "skolas",
+      "configs": [
+        {
+          "builder": "RELEASE",
+          "experimental": true,
+          "leader_board": true,
+          "board_group": "",
+          "arch": "X86_INTERNAL"
+        }
+      ]
+    },
+    {
+      "name": "skyrim",
+      "configs": [
+        {
+          "builder": "RELEASE",
+          "experimental": true,
+          "leader_board": true,
+          "board_group": "",
+          "arch": "X86_INTERNAL"
+        }
+      ]
+    },
+    {
+      "name": "skyrim-chausie",
+      "configs": [
+        {
+          "builder": "RELEASE",
+          "experimental": true,
+          "leader_board": false,
+          "board_group": "",
+          "arch": "X86_INTERNAL"
+        }
+      ]
+    },
+    {
+      "name": "skyrim-kernelnext",
+      "configs": [
+        {
+          "builder": "RELEASE",
+          "experimental": true,
+          "leader_board": false,
+          "board_group": "skyrim",
+          "arch": "X86_INTERNAL"
+        }
+      ]
+    },
+    {
       "name": "tael",
       "configs": [
         {
@@ -689,18 +617,6 @@
       "name": "unknown"
     },
     {
-      "name": "veyron_fievel",
-      "configs": [
-        {
-          "builder": "RELEASE",
-          "experimental": false,
-          "leader_board": false,
-          "board_group": "veyron",
-          "arch": "ARM_INTERNAL"
-        }
-      ]
-    },
-    {
       "name": "veyron_rialto",
       "configs": [
         {
@@ -713,18 +629,6 @@
       ]
     },
     {
-      "name": "veyron_tiger",
-      "configs": [
-        {
-          "builder": "RELEASE",
-          "experimental": false,
-          "leader_board": false,
-          "board_group": "veyron",
-          "arch": "ARM_INTERNAL"
-        }
-      ]
-    },
-    {
       "name": "wizpig",
       "configs": [
         {
@@ -769,6 +673,14 @@
           "release_builder_test_pool": "bvt",
           "board_id": 7168,
           "is_active": true
+        },
+        {
+          "board_name": "adlrvp",
+          "name": "adlrvp_mchp",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7168,
+          "is_active": true
         }
       ]
     },
@@ -913,23 +825,6 @@
       ]
     },
     {
-      "name": "asurada-zephyr",
-      "reference_board_name": "asurada-zephyr",
-      "arch": "ARM_INTERNAL",
-      "builder": "RELEASE",
-      "experimental": false,
-      "models": [
-        {
-          "board_name": "asurada-zephyr",
-          "name": "hayato",
-          "cq_test_enabled": false,
-          "release_builder_test_pool": "bvt",
-          "board_id": 7198,
-          "is_active": true
-        }
-      ]
-    },
-    {
       "name": "atlas",
       "reference_board_name": "atlas",
       "arch": "X86_INTERNAL",
@@ -1214,6 +1109,62 @@
       ]
     },
     {
+      "name": "bob",
+      "reference_board_name": "bob",
+      "arch": "ARM_INTERNAL",
+      "builder": "RELEASE",
+      "experimental": false,
+      "models": [
+        {
+          "board_name": "bob",
+          "name": "bob",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": true,
+          "release_builder_test_pool": "bvt",
+          "board_id": 292,
+          "is_active": true
+        }
+      ]
+    },
+    {
+      "name": "brask",
+      "reference_board_name": "brask",
+      "arch": "X86_INTERNAL",
+      "builder": "RELEASE",
+      "experimental": false,
+      "models": [
+        {
+          "board_name": "brask",
+          "name": "brask",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7196,
+          "is_active": true
+        }
+      ]
+    },
+    {
       "name": "brya",
       "reference_board_name": "brya",
       "arch": "X86_INTERNAL",
@@ -1230,6 +1181,52 @@
         },
         {
           "board_name": "brya",
+          "name": "anahera",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": true,
+          "release_builder_test_pool": "bvt",
+          "board_id": 459,
+          "is_active": true
+        },
+        {
+          "board_name": "brya",
+          "name": "anahera4es",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": true,
+          "release_builder_test_pool": "bvt",
+          "board_id": 459,
+          "is_active": true
+        },
+        {
+          "board_name": "brya",
+          "name": "banshee",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 459,
+          "is_active": true
+        },
+        {
+          "board_name": "brya",
           "name": "brya",
           "test_suites": [
             "sanity",
@@ -1249,7 +1246,7 @@
         },
         {
           "board_name": "brya",
-          "name": "felwinter",
+          "name": "brya4es",
           "test_suites": [
             "sanity",
             "bvt-inline",
@@ -1268,7 +1265,7 @@
         },
         {
           "board_name": "brya",
-          "name": "gimble",
+          "name": "brya4esti50",
           "cq_test_enabled": false,
           "release_builder_test_pool": "bvt",
           "board_id": 459,
@@ -1276,8 +1273,92 @@
         },
         {
           "board_name": "brya",
+          "name": "crota",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 459,
+          "is_active": true
+        },
+        {
+          "board_name": "brya",
+          "name": "crota360",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 459,
+          "is_active": true
+        },
+        {
+          "board_name": "brya",
+          "name": "felwinter",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": true,
+          "release_builder_test_pool": "bvt",
+          "board_id": 459,
+          "is_active": true
+        },
+        {
+          "board_name": "brya",
+          "name": "gimble",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": true,
+          "release_builder_test_pool": "bvt",
+          "board_id": 459,
+          "is_active": true
+        },
+        {
+          "board_name": "brya",
+          "name": "gimble4es",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": true,
+          "release_builder_test_pool": "bvt",
+          "board_id": 459,
+          "is_active": true
+        },
+        {
+          "board_name": "brya",
           "name": "kano",
-          "cq_test_enabled": false,
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": true,
           "release_builder_test_pool": "bvt",
           "board_id": 459,
           "is_active": true
@@ -1285,7 +1366,37 @@
         {
           "board_name": "brya",
           "name": "primus",
-          "cq_test_enabled": false,
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": true,
+          "release_builder_test_pool": "bvt",
+          "board_id": 459,
+          "is_active": true
+        },
+        {
+          "board_name": "brya",
+          "name": "primus4es",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": true,
           "release_builder_test_pool": "bvt",
           "board_id": 459,
           "is_active": true
@@ -1293,7 +1404,37 @@
         {
           "board_name": "brya",
           "name": "redrix",
-          "cq_test_enabled": false,
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": true,
+          "release_builder_test_pool": "bvt",
+          "board_id": 459,
+          "is_active": true
+        },
+        {
+          "board_name": "brya",
+          "name": "redrix4es",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": true,
           "release_builder_test_pool": "bvt",
           "board_id": 459,
           "is_active": true
@@ -1301,10 +1442,273 @@
         {
           "board_name": "brya",
           "name": "taeko",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": true,
+          "release_builder_test_pool": "bvt",
+          "board_id": 459,
+          "is_active": true
+        },
+        {
+          "board_name": "brya",
+          "name": "taeko4es",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": true,
+          "release_builder_test_pool": "bvt",
+          "board_id": 459,
+          "is_active": true
+        },
+        {
+          "board_name": "brya",
+          "name": "taniks",
           "cq_test_enabled": false,
           "release_builder_test_pool": "bvt",
           "board_id": 459,
           "is_active": true
+        },
+        {
+          "board_name": "brya",
+          "name": "tarlo",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 459,
+          "is_active": true
+        },
+        {
+          "board_name": "brya",
+          "name": "vell",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 459,
+          "is_active": true
+        },
+        {
+          "board_name": "brya",
+          "name": "volmar",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 459,
+          "is_active": true
+        },
+        {
+          "board_name": "brya",
+          "name": "zavala",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 459,
+          "is_active": true
+        }
+      ]
+    },
+    {
+      "name": "brya-lvm-stateful",
+      "reference_board_name": "brya-lvm-stateful",
+      "arch": "X86_INTERNAL",
+      "builder": "RELEASE",
+      "experimental": true,
+      "models": [
+        {
+          "board_name": "brya-lvm-stateful",
+          "name": "anahera",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7214,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-lvm-stateful",
+          "name": "anahera4es",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7214,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-lvm-stateful",
+          "name": "banshee",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7214,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-lvm-stateful",
+          "name": "brya",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7214,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-lvm-stateful",
+          "name": "brya4es",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7214,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-lvm-stateful",
+          "name": "brya4esti50",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7214,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-lvm-stateful",
+          "name": "crota",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7214,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-lvm-stateful",
+          "name": "crota360",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7214,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-lvm-stateful",
+          "name": "felwinter",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7214,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-lvm-stateful",
+          "name": "gimble",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7214,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-lvm-stateful",
+          "name": "gimble4es",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7214,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-lvm-stateful",
+          "name": "kano",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7214,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-lvm-stateful",
+          "name": "primus",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7214,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-lvm-stateful",
+          "name": "primus4es",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7214,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-lvm-stateful",
+          "name": "redrix",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7214,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-lvm-stateful",
+          "name": "redrix4es",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7214,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-lvm-stateful",
+          "name": "taeko",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7214,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-lvm-stateful",
+          "name": "taeko4es",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7214,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-lvm-stateful",
+          "name": "taniks",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7214,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-lvm-stateful",
+          "name": "tarlo",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7214,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-lvm-stateful",
+          "name": "vell",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7214,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-lvm-stateful",
+          "name": "volmar",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7214,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-lvm-stateful",
+          "name": "zavala",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7214,
+          "is_active": true
         }
       ]
     },
@@ -1325,6 +1729,30 @@
         },
         {
           "board_name": "brya-manatee",
+          "name": "anahera",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7187,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-manatee",
+          "name": "anahera4es",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7187,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-manatee",
+          "name": "banshee",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7187,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-manatee",
           "name": "brya",
           "cq_test_enabled": false,
           "release_builder_test_pool": "bvt",
@@ -1333,6 +1761,38 @@
         },
         {
           "board_name": "brya-manatee",
+          "name": "brya4es",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7187,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-manatee",
+          "name": "brya4esti50",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7187,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-manatee",
+          "name": "crota",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7187,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-manatee",
+          "name": "crota360",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7187,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-manatee",
           "name": "felwinter",
           "cq_test_enabled": false,
           "release_builder_test_pool": "bvt",
@@ -1349,6 +1809,14 @@
         },
         {
           "board_name": "brya-manatee",
+          "name": "gimble4es",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7187,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-manatee",
           "name": "kano",
           "cq_test_enabled": false,
           "release_builder_test_pool": "bvt",
@@ -1365,6 +1833,14 @@
         },
         {
           "board_name": "brya-manatee",
+          "name": "primus4es",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7187,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-manatee",
           "name": "redrix",
           "cq_test_enabled": false,
           "release_builder_test_pool": "bvt",
@@ -1373,11 +1849,120 @@
         },
         {
           "board_name": "brya-manatee",
+          "name": "redrix4es",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7187,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-manatee",
           "name": "taeko",
           "cq_test_enabled": false,
           "release_builder_test_pool": "bvt",
           "board_id": 7187,
           "is_active": true
+        },
+        {
+          "board_name": "brya-manatee",
+          "name": "taeko4es",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7187,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-manatee",
+          "name": "taniks",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7187,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-manatee",
+          "name": "tarlo",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7187,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-manatee",
+          "name": "vell",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7187,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-manatee",
+          "name": "volmar",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7187,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-manatee",
+          "name": "zavala",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7187,
+          "is_active": true
+        }
+      ]
+    },
+    {
+      "name": "brya-zephyr",
+      "reference_board_name": "brya-zephyr",
+      "arch": "X86_INTERNAL",
+      "builder": "RELEASE",
+      "experimental": true,
+      "models": [
+        {
+          "board_name": "brya-zephyr",
+          "name": "brya",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7217,
+          "is_active": true
+        },
+        {
+          "board_name": "brya-zephyr",
+          "name": "bryati50",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7217,
+          "is_active": true
+        }
+      ]
+    },
+    {
+      "name": "cave",
+      "reference_board_name": "cave",
+      "arch": "X86_INTERNAL",
+      "builder": "RELEASE",
+      "experimental": false,
+      "models": [
+        {
+          "board_name": "cave",
+          "name": "cave",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": true,
+          "release_builder_test_pool": "bvt",
+          "board_id": 267,
+          "is_active": true
         }
       ]
     },
@@ -1399,6 +1984,17 @@
         {
           "board_name": "cherry",
           "name": "tomato",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
           "cq_test_enabled": false,
           "release_builder_test_pool": "bvt",
           "board_id": 7163,
@@ -1407,6 +2003,31 @@
       ]
     },
     {
+      "name": "cherry64",
+      "reference_board_name": "cherry64",
+      "arch": "ARM_INTERNAL",
+      "builder": "RELEASE",
+      "experimental": true,
+      "models": [
+        {
+          "board_name": "cherry64",
+          "name": "cherry",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7216,
+          "is_active": true
+        },
+        {
+          "board_name": "cherry64",
+          "name": "tomato",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7216,
+          "is_active": true
+        }
+      ]
+    },
+    {
       "name": "coral",
       "reference_board_name": "coral",
       "arch": "X86_INTERNAL",
@@ -1707,6 +2328,301 @@
       ]
     },
     {
+      "name": "coral-kernelnext",
+      "reference_board_name": "coral-kernelnext",
+      "arch": "X86_INTERNAL",
+      "builder": "RELEASE",
+      "experimental": true,
+      "models": [
+        {
+          "board_name": "coral-kernelnext",
+          "name": "astronaut",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": true,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7180,
+          "is_active": true
+        },
+        {
+          "board_name": "coral-kernelnext",
+          "name": "babymega",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7180,
+          "is_active": true
+        },
+        {
+          "board_name": "coral-kernelnext",
+          "name": "babytiger",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7180,
+          "is_active": true
+        },
+        {
+          "board_name": "coral-kernelnext",
+          "name": "blacktip",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7180,
+          "is_active": true
+        },
+        {
+          "board_name": "coral-kernelnext",
+          "name": "blacktip360",
+          "test_suites": [
+            "bvt-arc",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7180,
+          "is_active": true
+        },
+        {
+          "board_name": "coral-kernelnext",
+          "name": "blacktiplte",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7180,
+          "is_active": true
+        },
+        {
+          "board_name": "coral-kernelnext",
+          "name": "blue",
+          "test_suites": [
+            "au"
+          ],
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7180,
+          "is_active": true
+        },
+        {
+          "board_name": "coral-kernelnext",
+          "name": "bruce",
+          "test_suites": [
+            "bvt-inline",
+            "bvt-tast-cq"
+          ],
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7180,
+          "is_active": true
+        },
+        {
+          "board_name": "coral-kernelnext",
+          "name": "epaulette",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7180,
+          "is_active": true
+        },
+        {
+          "board_name": "coral-kernelnext",
+          "name": "lava",
+          "test_suites": [
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-arc",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7180,
+          "is_active": true
+        },
+        {
+          "board_name": "coral-kernelnext",
+          "name": "nasher",
+          "test_suites": [
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-arc",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7180,
+          "is_active": true
+        },
+        {
+          "board_name": "coral-kernelnext",
+          "name": "nasher360",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7180,
+          "is_active": true
+        },
+        {
+          "board_name": "coral-kernelnext",
+          "name": "porbeagle",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7180,
+          "is_active": true
+        },
+        {
+          "board_name": "coral-kernelnext",
+          "name": "rabbid",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7180,
+          "is_active": true
+        },
+        {
+          "board_name": "coral-kernelnext",
+          "name": "robo",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7180,
+          "is_active": true
+        },
+        {
+          "board_name": "coral-kernelnext",
+          "name": "robo360",
+          "test_suites": [
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-arc",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7180,
+          "is_active": true
+        },
+        {
+          "board_name": "coral-kernelnext",
+          "name": "santa",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7180,
+          "is_active": true
+        },
+        {
+          "board_name": "coral-kernelnext",
+          "name": "whitetip",
+          "test_suites": [
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-arc",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7180,
+          "is_active": true
+        }
+      ]
+    },
+    {
       "name": "dedede",
       "reference_board_name": "dedede",
       "arch": "X86_INTERNAL",
@@ -1716,6 +2632,17 @@
         {
           "board_name": "dedede",
           "name": "beetley",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
           "cq_test_enabled": false,
           "release_builder_test_pool": "bvt",
           "board_id": 419,
@@ -1742,6 +2669,14 @@
         },
         {
           "board_name": "dedede",
+          "name": "bookem",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 419,
+          "is_active": true
+        },
+        {
+          "board_name": "dedede",
           "name": "boten",
           "test_suites": [
             "sanity",
@@ -1780,6 +2715,25 @@
         },
         {
           "board_name": "dedede",
+          "name": "bugzzy",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": true,
+          "release_builder_test_pool": "bvt",
+          "board_id": 419,
+          "is_active": true
+        },
+        {
+          "board_name": "dedede",
           "name": "cret",
           "test_suites": [
             "sanity",
@@ -1913,6 +2867,25 @@
         },
         {
           "board_name": "dedede",
+          "name": "galith360",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 419,
+          "is_active": true
+        },
+        {
+          "board_name": "dedede",
           "name": "gallop",
           "test_suites": [
             "sanity",
@@ -1933,6 +2906,17 @@
         {
           "board_name": "dedede",
           "name": "galnat",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
           "cq_test_enabled": false,
           "release_builder_test_pool": "bvt",
           "board_id": 419,
@@ -1941,6 +2925,36 @@
         {
           "board_name": "dedede",
           "name": "galtic",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 419,
+          "is_active": true
+        },
+        {
+          "board_name": "dedede",
+          "name": "galtic360",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
           "cq_test_enabled": false,
           "release_builder_test_pool": "bvt",
           "board_id": 419,
@@ -2044,7 +3058,18 @@
         {
           "board_name": "dedede",
           "name": "maglet",
-          "cq_test_enabled": false,
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": true,
           "release_builder_test_pool": "bvt",
           "board_id": 419,
           "is_active": true
@@ -2109,7 +3134,18 @@
         {
           "board_name": "dedede",
           "name": "magneto",
-          "cq_test_enabled": false,
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": true,
           "release_builder_test_pool": "bvt",
           "board_id": 419,
           "is_active": true
@@ -2173,6 +3209,14 @@
         },
         {
           "board_name": "dedede",
+          "name": "pasara",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 419,
+          "is_active": true
+        },
+        {
+          "board_name": "dedede",
           "name": "pirette",
           "test_suites": [
             "sanity",
@@ -2304,6 +3348,31 @@
       ]
     },
     {
+      "name": "draco",
+      "reference_board_name": "draco",
+      "arch": "X86_INTERNAL",
+      "builder": "RELEASE",
+      "experimental": true,
+      "models": [
+        {
+          "board_name": "draco",
+          "name": "agah",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7215,
+          "is_active": true
+        },
+        {
+          "board_name": "draco",
+          "name": "draco",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7215,
+          "is_active": true
+        }
+      ]
+    },
+    {
       "name": "drallion",
       "reference_board_name": "drallion",
       "arch": "X86_INTERNAL",
@@ -2547,34 +3616,6 @@
       ]
     },
     {
-      "name": "eve-kernelnext",
-      "reference_board_name": "eve-kernelnext",
-      "arch": "X86_INTERNAL",
-      "builder": "RELEASE",
-      "experimental": true,
-      "models": [
-        {
-          "board_name": "eve-kernelnext",
-          "name": "eve",
-          "test_suites": [
-            "sanity",
-            "bvt-inline",
-            "bvt-tast-cq",
-            "bvt-installer",
-            "bvt-arc",
-            "au",
-            "bvt-cq",
-            "bvt-perbuild",
-            "bvt-tast-informational"
-          ],
-          "cq_test_enabled": false,
-          "release_builder_test_pool": "bvt",
-          "board_id": 446,
-          "is_active": true
-        }
-      ]
-    },
-    {
       "name": "eve-kvm",
       "reference_board_name": "eve-kvm",
       "arch": "X86_INTERNAL",
@@ -2748,6 +3789,55 @@
       ]
     },
     {
+      "name": "fizz-kernelnext",
+      "reference_board_name": "fizz-kernelnext",
+      "arch": "X86_INTERNAL",
+      "builder": "RELEASE",
+      "experimental": true,
+      "models": [
+        {
+          "board_name": "fizz-kernelnext",
+          "name": "jax",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7224,
+          "is_active": true
+        },
+        {
+          "board_name": "fizz-kernelnext",
+          "name": "kench",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7224,
+          "is_active": true
+        },
+        {
+          "board_name": "fizz-kernelnext",
+          "name": "sion",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7224,
+          "is_active": true
+        },
+        {
+          "board_name": "fizz-kernelnext",
+          "name": "teemo",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7224,
+          "is_active": true
+        },
+        {
+          "board_name": "fizz-kernelnext",
+          "name": "wukong",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7224,
+          "is_active": true
+        }
+      ]
+    },
+    {
       "name": "fizz-labstation",
       "reference_board_name": "fizz-labstation",
       "arch": "X86_INTERNAL",
@@ -3293,6 +4383,14 @@
       "models": [
         {
           "board_name": "guybrush",
+          "name": "dewatt",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7148,
+          "is_active": true
+        },
+        {
+          "board_name": "guybrush",
           "name": "guybrush",
           "cq_test_enabled": false,
           "release_builder_test_pool": "bvt",
@@ -3310,6 +4408,17 @@
         {
           "board_name": "guybrush",
           "name": "nipperkin",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
           "cq_test_enabled": false,
           "release_builder_test_pool": "bvt",
           "board_id": 7148,
@@ -3918,6 +5027,119 @@
       ]
     },
     {
+      "name": "hatch-arc-t",
+      "reference_board_name": "hatch-arc-t",
+      "arch": "X86_INTERNAL",
+      "builder": "RELEASE",
+      "experimental": true,
+      "models": [
+        {
+          "board_name": "hatch-arc-t",
+          "name": "akemi",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7222,
+          "is_active": true
+        },
+        {
+          "board_name": "hatch-arc-t",
+          "name": "dragonair",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7222,
+          "is_active": true
+        },
+        {
+          "board_name": "hatch-arc-t",
+          "name": "dratini",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7222,
+          "is_active": true
+        },
+        {
+          "board_name": "hatch-arc-t",
+          "name": "hatch",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7222,
+          "is_active": true
+        },
+        {
+          "board_name": "hatch-arc-t",
+          "name": "helios",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7222,
+          "is_active": true
+        },
+        {
+          "board_name": "hatch-arc-t",
+          "name": "helios_diskswap",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7222,
+          "is_active": true
+        },
+        {
+          "board_name": "hatch-arc-t",
+          "name": "jinlon",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7222,
+          "is_active": true
+        },
+        {
+          "board_name": "hatch-arc-t",
+          "name": "kindred",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7222,
+          "is_active": true
+        },
+        {
+          "board_name": "hatch-arc-t",
+          "name": "kled",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7222,
+          "is_active": true
+        },
+        {
+          "board_name": "hatch-arc-t",
+          "name": "kohaku",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7222,
+          "is_active": true
+        },
+        {
+          "board_name": "hatch-arc-t",
+          "name": "nightfury",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7222,
+          "is_active": true
+        },
+        {
+          "board_name": "hatch-arc-t",
+          "name": "unprovisioned_dratini",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7222,
+          "is_active": true
+        },
+        {
+          "board_name": "hatch-arc-t",
+          "name": "unprovisioned_jinlon",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7222,
+          "is_active": true
+        }
+      ]
+    },
+    {
       "name": "hatch-blueznext",
       "reference_board_name": "hatch-blueznext",
       "arch": "X86_INTERNAL",
@@ -4461,103 +5683,6 @@
       ]
     },
     {
-      "name": "hatch-manatee",
-      "reference_board_name": "hatch-manatee",
-      "arch": "X86_INTERNAL",
-      "builder": "RELEASE",
-      "experimental": true,
-      "models": [
-        {
-          "board_name": "hatch-manatee",
-          "name": "akemi",
-          "cq_test_enabled": false,
-          "release_builder_test_pool": "bvt",
-          "board_id": 7171,
-          "is_active": true
-        },
-        {
-          "board_name": "hatch-manatee",
-          "name": "dragonair",
-          "cq_test_enabled": false,
-          "release_builder_test_pool": "bvt",
-          "board_id": 7171,
-          "is_active": true
-        },
-        {
-          "board_name": "hatch-manatee",
-          "name": "dratini",
-          "cq_test_enabled": false,
-          "release_builder_test_pool": "bvt",
-          "board_id": 7171,
-          "is_active": true
-        },
-        {
-          "board_name": "hatch-manatee",
-          "name": "hatch",
-          "cq_test_enabled": false,
-          "release_builder_test_pool": "bvt",
-          "board_id": 7171,
-          "is_active": true
-        },
-        {
-          "board_name": "hatch-manatee",
-          "name": "helios",
-          "cq_test_enabled": false,
-          "release_builder_test_pool": "bvt",
-          "board_id": 7171,
-          "is_active": true
-        },
-        {
-          "board_name": "hatch-manatee",
-          "name": "helios_diskswap",
-          "cq_test_enabled": false,
-          "release_builder_test_pool": "bvt",
-          "board_id": 7171,
-          "is_active": true
-        },
-        {
-          "board_name": "hatch-manatee",
-          "name": "jinlon",
-          "cq_test_enabled": false,
-          "release_builder_test_pool": "bvt",
-          "board_id": 7171,
-          "is_active": true
-        },
-        {
-          "board_name": "hatch-manatee",
-          "name": "kindred",
-          "cq_test_enabled": false,
-          "release_builder_test_pool": "bvt",
-          "board_id": 7171,
-          "is_active": true
-        },
-        {
-          "board_name": "hatch-manatee",
-          "name": "kled",
-          "cq_test_enabled": false,
-          "release_builder_test_pool": "bvt",
-          "board_id": 7171,
-          "is_active": true
-        },
-        {
-          "board_name": "hatch-manatee",
-          "name": "kohaku",
-          "cq_test_enabled": false,
-          "release_builder_test_pool": "bvt",
-          "board_id": 7171,
-          "is_active": true
-        },
-        {
-          "board_name": "hatch-manatee",
-          "name": "nightfury",
-          "cq_test_enabled": false,
-          "release_builder_test_pool": "bvt",
-          "board_id": 7171,
-          "is_active": true
-        }
-      ]
-    },
-    {
       "name": "jacuzzi",
       "reference_board_name": "jacuzzi",
       "arch": "ARM_INTERNAL",
@@ -4780,6 +5905,25 @@
         },
         {
           "board_name": "jacuzzi",
+          "name": "pico6",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 401,
+          "is_active": true
+        },
+        {
+          "board_name": "jacuzzi",
           "name": "stern",
           "cq_test_enabled": false,
           "release_builder_test_pool": "bvt",
@@ -5052,6 +6196,14 @@
         },
         {
           "board_name": "jacuzzi-kernelnext",
+          "name": "pico6",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7172,
+          "is_active": true
+        },
+        {
+          "board_name": "jacuzzi-kernelnext",
           "name": "stern",
           "test_suites": [
             "sanity",
@@ -5180,6 +6332,17 @@
         {
           "board_name": "keeby",
           "name": "gooey",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
           "cq_test_enabled": false,
           "release_builder_test_pool": "bvt",
           "board_id": 7175,
@@ -5188,6 +6351,17 @@
         {
           "board_name": "keeby",
           "name": "habokay",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
           "cq_test_enabled": false,
           "release_builder_test_pool": "bvt",
           "board_id": 7175,
@@ -5196,6 +6370,17 @@
         {
           "board_name": "keeby",
           "name": "haboki",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
           "cq_test_enabled": false,
           "release_builder_test_pool": "bvt",
           "board_id": 7175,
@@ -5212,6 +6397,104 @@
       ]
     },
     {
+      "name": "kevin",
+      "reference_board_name": "kevin",
+      "arch": "ARM_INTERNAL",
+      "builder": "RELEASE",
+      "experimental": false,
+      "models": [
+        {
+          "board_name": "kevin",
+          "name": "kevin",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": true,
+          "release_builder_test_pool": "bvt",
+          "board_id": 273,
+          "is_active": true
+        }
+      ]
+    },
+    {
+      "name": "kevin-kernelnext",
+      "reference_board_name": "kevin-kernelnext",
+      "arch": "ARM_INTERNAL",
+      "builder": "RELEASE",
+      "experimental": false,
+      "models": [
+        {
+          "board_name": "kevin-kernelnext",
+          "name": "kevin",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": true,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7199,
+          "is_active": true
+        }
+      ]
+    },
+    {
+      "name": "kevin-userdebug",
+      "reference_board_name": "kevin-userdebug",
+      "arch": "ARM_INTERNAL",
+      "builder": "RELEASE",
+      "experimental": true,
+      "models": [
+        {
+          "board_name": "kevin-userdebug",
+          "name": "kevin",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7162,
+          "is_active": true
+        },
+        {
+          "board_name": "kevin-userdebug",
+          "name": "kevin1",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7162,
+          "is_active": true
+        }
+      ]
+    },
+    {
+      "name": "kevin64",
+      "reference_board_name": "kevin64",
+      "arch": "ARM_INTERNAL",
+      "builder": "RELEASE",
+      "experimental": true,
+      "models": [
+        {
+          "board_name": "kevin64",
+          "name": "kevin",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 367,
+          "is_active": true
+        }
+      ]
+    },
+    {
       "name": "kukui",
       "reference_board_name": "kukui",
       "arch": "ARM_INTERNAL",
@@ -5921,6 +7204,14 @@
         },
         {
           "board_name": "octopus",
+          "name": "amptone",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 354,
+          "is_active": true
+        },
+        {
+          "board_name": "octopus",
           "name": "apel",
           "test_suites": [
             "sanity",
@@ -5939,14 +7230,6 @@
         },
         {
           "board_name": "octopus",
-          "name": "apel-e",
-          "cq_test_enabled": false,
-          "release_builder_test_pool": "bvt",
-          "board_id": 354,
-          "is_active": true
-        },
-        {
-          "board_name": "octopus",
           "name": "apele",
           "cq_test_enabled": false,
           "release_builder_test_pool": "bvt",
@@ -6572,6 +7855,14 @@
         },
         {
           "board_name": "octopus-arc-r",
+          "name": "amptone",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7201,
+          "is_active": true
+        },
+        {
+          "board_name": "octopus-arc-r",
           "name": "apel",
           "cq_test_enabled": false,
           "release_builder_test_pool": "bvt",
@@ -6972,6 +8263,14 @@
         },
         {
           "board_name": "octopus-kernelnext",
+          "name": "amptone",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7200,
+          "is_active": true
+        },
+        {
+          "board_name": "octopus-kernelnext",
           "name": "apel",
           "test_suites": [
             "sanity",
@@ -8292,6 +9591,17 @@
         {
           "board_name": "sarien-kernelnext",
           "name": "arcada",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
           "cq_test_enabled": false,
           "release_builder_test_pool": "bvt",
           "board_id": 7210,
@@ -8389,6 +9699,39 @@
       ]
     },
     {
+      "name": "scarlet-kernelnext",
+      "reference_board_name": "scarlet-kernelnext",
+      "arch": "ARM_INTERNAL",
+      "builder": "RELEASE",
+      "experimental": true,
+      "models": [
+        {
+          "board_name": "scarlet-kernelnext",
+          "name": "dru",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7212,
+          "is_active": true
+        },
+        {
+          "board_name": "scarlet-kernelnext",
+          "name": "druwl",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7212,
+          "is_active": true
+        },
+        {
+          "board_name": "scarlet-kernelnext",
+          "name": "dumo",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7212,
+          "is_active": true
+        }
+      ]
+    },
+    {
       "name": "snappy",
       "reference_board_name": "snappy",
       "arch": "X86_INTERNAL",
@@ -8458,6 +9801,17 @@
         {
           "board_name": "snappy-kernelnext",
           "name": "snappy",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
           "cq_test_enabled": false,
           "release_builder_test_pool": "bvt",
           "board_id": 7179,
@@ -8558,6 +9912,36 @@
         {
           "board_name": "strongbad",
           "name": "mrbland",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 461,
+          "is_active": true
+        },
+        {
+          "board_name": "strongbad",
+          "name": "quackingstick",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
           "cq_test_enabled": false,
           "release_builder_test_pool": "bvt",
           "board_id": 461,
@@ -8566,6 +9950,17 @@
         {
           "board_name": "strongbad",
           "name": "wormdingler",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
           "cq_test_enabled": false,
           "release_builder_test_pool": "bvt",
           "board_id": 461,
@@ -8574,14 +9969,93 @@
       ]
     },
     {
+      "name": "strongbad-kernelnext",
+      "reference_board_name": "strongbad-kernelnext",
+      "arch": "ARM_INTERNAL",
+      "builder": "RELEASE",
+      "experimental": false,
+      "models": [
+        {
+          "board_name": "strongbad-kernelnext",
+          "name": "coachz",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7213,
+          "is_active": true
+        },
+        {
+          "board_name": "strongbad-kernelnext",
+          "name": "homestar",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7213,
+          "is_active": true
+        },
+        {
+          "board_name": "strongbad-kernelnext",
+          "name": "mrbland",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7213,
+          "is_active": true
+        },
+        {
+          "board_name": "strongbad-kernelnext",
+          "name": "quackingstick",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7213,
+          "is_active": true
+        },
+        {
+          "board_name": "strongbad-kernelnext",
+          "name": "wormdingler",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7213,
+          "is_active": true
+        }
+      ]
+    },
+    {
       "name": "trogdor",
       "reference_board_name": "trogdor",
       "arch": "ARM_INTERNAL",
       "builder": "RELEASE",
-      "experimental": false,
+      "experimental": true,
       "models": [
         {
           "board_name": "trogdor",
+          "name": "kingoftown",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 418,
+          "is_active": true
+        },
+        {
+          "board_name": "trogdor",
           "name": "lazor",
           "test_suites": [
             "sanity",
@@ -8621,6 +10095,17 @@
         {
           "board_name": "trogdor",
           "name": "pazquel",
+          "test_suites": [
+            "sanity",
+            "bvt-inline",
+            "bvt-tast-cq",
+            "bvt-installer",
+            "bvt-arc",
+            "au",
+            "bvt-cq",
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
           "cq_test_enabled": false,
           "release_builder_test_pool": "bvt",
           "board_id": 418,
@@ -8664,6 +10149,14 @@
       "models": [
         {
           "board_name": "trogdor-arc-r",
+          "name": "kingoftown",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7189,
+          "is_active": true
+        },
+        {
+          "board_name": "trogdor-arc-r",
           "name": "lazor",
           "cq_test_enabled": false,
           "release_builder_test_pool": "bvt",
@@ -8723,6 +10216,14 @@
       "models": [
         {
           "board_name": "trogdor-connectivitynext",
+          "name": "kingoftown",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7203,
+          "is_active": true
+        },
+        {
+          "board_name": "trogdor-connectivitynext",
           "name": "lazor",
           "cq_test_enabled": false,
           "release_builder_test_pool": "bvt",
@@ -8768,10 +10269,18 @@
       "reference_board_name": "trogdor-kernelnext",
       "arch": "ARM_INTERNAL",
       "builder": "RELEASE",
-      "experimental": true,
+      "experimental": false,
       "models": [
         {
           "board_name": "trogdor-kernelnext",
+          "name": "kingoftown",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 7159,
+          "is_active": true
+        },
+        {
+          "board_name": "trogdor-kernelnext",
           "name": "lazor",
           "test_suites": [
             "sanity",
@@ -8792,6 +10301,10 @@
         {
           "board_name": "trogdor-kernelnext",
           "name": "limozeen",
+          "test_suites": [
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
           "cq_test_enabled": false,
           "release_builder_test_pool": "bvt",
           "board_id": 7159,
@@ -8808,6 +10321,10 @@
         {
           "board_name": "trogdor-kernelnext",
           "name": "pompom",
+          "test_suites": [
+            "bvt-perbuild",
+            "bvt-tast-informational"
+          ],
           "cq_test_enabled": false,
           "release_builder_test_pool": "bvt",
           "board_id": 7159,
@@ -8857,6 +10374,14 @@
       "models": [
         {
           "board_name": "trogdor64",
+          "name": "kingoftown",
+          "cq_test_enabled": false,
+          "release_builder_test_pool": "bvt",
+          "board_id": 462,
+          "is_active": true
+        },
+        {
+          "board_name": "trogdor64",
           "name": "lazor",
           "test_suites": [
             "sanity",
@@ -9834,39 +11359,6 @@
       ]
     },
     {
-      "name": "volteer-zephyr",
-      "reference_board_name": "volteer-zephyr",
-      "arch": "X86_INTERNAL",
-      "builder": "RELEASE",
-      "experimental": true,
-      "models": [
-        {
-          "board_name": "volteer-zephyr",
-          "name": "delbin",
-          "cq_test_enabled": false,
-          "release_builder_test_pool": "bvt",
-          "board_id": 7181,
-          "is_active": true
-        },
-        {
-          "board_name": "volteer-zephyr",
-          "name": "volteer2",
-          "cq_test_enabled": false,
-          "release_builder_test_pool": "bvt",
-          "board_id": 7181,
-          "is_active": true
-        },
-        {
-          "board_name": "volteer-zephyr",
-          "name": "volteer2_ti50",
-          "cq_test_enabled": false,
-          "release_builder_test_pool": "bvt",
-          "board_id": 7181,
-          "is_active": true
-        }
-      ]
-    },
-    {
       "name": "zork",
       "reference_board_name": "zork",
       "arch": "X86_INTERNAL",
diff --git a/config/luci-scheduler.cfg b/config/luci-scheduler.cfg
index af0f6a0..a2601cb 100644
--- a/config/luci-scheduler.cfg
+++ b/config/luci-scheduler.cfg
@@ -48,9 +48,9 @@
   schedule: "with 5m interval"
   gitiles: {
     repo: "https://chromium.googlesource.com/chromium/src"
-    refs: "regexp:refs/tags/90\\..*"
+    refs: "regexp:refs/tags/96\\..*"
   }
-  triggers: "release-R90-13816.B-chell-chrome-no-afdo-uprev-pre-flight-branch"
+  triggers: "release-R96-14268.B-chell-chrome-no-afdo-uprev-pre-flight-branch"
 }
 
 trigger {
@@ -97,10 +97,10 @@
   schedule: "with 5m interval"
   gitiles: {
     repo: "https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay"
-    refs: "regexp:refs/heads/release-R90-13816.B\\..*"
-    path_regexps: "chromeos-base/chromeos-chrome/chromeos-chrome-90.*.ebuild"
+    refs: "regexp:refs/heads/release-R100-14526.B\\..*"
+    path_regexps: "chromeos-base/chromeos-chrome/chromeos-chrome-100.*.ebuild"
   }
-  triggers: "release-R90-13816.B-master-release"
+  triggers: "release-R100-14526.B-master-release"
 }
 
 trigger {
@@ -110,38 +110,38 @@
   schedule: "with 5m interval"
   gitiles: {
     repo: "https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay"
-    refs: "regexp:refs/heads/release-R93-14092.B\\..*"
-    path_regexps: "chromeos-base/chromeos-chrome/chromeos-chrome-93.*.ebuild"
-  }
-  triggers: "release-R93-14092.B-master-release"
-}
-
-trigger {
-  id: "trigger_7"
-  realm: "cbb-jobs"
-  acl_sets: "default"
-  schedule: "with 5m interval"
-  gitiles: {
-    repo: "https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay"
-    refs: "regexp:refs/heads/release-R94-14150.B\\..*"
-    path_regexps: "chromeos-base/chromeos-chrome/chromeos-chrome-94.*.ebuild"
-  }
-  triggers: "release-R94-14150.B-master-release"
-}
-
-trigger {
-  id: "trigger_8"
-  realm: "cbb-jobs"
-  acl_sets: "default"
-  schedule: "with 5m interval"
-  gitiles: {
-    repo: "https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay"
     refs: "regexp:refs/heads/release-R96-14268.B\\..*"
     path_regexps: "chromeos-base/chromeos-chrome/chromeos-chrome-96.*.ebuild"
   }
   triggers: "release-R96-14268.B-master-release"
 }
 
+trigger {
+  id: "trigger_7"
+  realm: "cbb-jobs"
+  acl_sets: "default"
+  schedule: "with 5m interval"
+  gitiles: {
+    repo: "https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay"
+    refs: "regexp:refs/heads/release-R98-14388.B\\..*"
+    path_regexps: "chromeos-base/chromeos-chrome/chromeos-chrome-98.*.ebuild"
+  }
+  triggers: "release-R98-14388.B-master-release"
+}
+
+trigger {
+  id: "trigger_8"
+  realm: "cbb-jobs"
+  acl_sets: "default"
+  schedule: "with 5m interval"
+  gitiles: {
+    repo: "https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay"
+    refs: "regexp:refs/heads/release-R99-14469.B\\..*"
+    path_regexps: "chromeos-base/chromeos-chrome/chromeos-chrome-99.*.ebuild"
+  }
+  triggers: "release-R99-14469.B-master-release"
+}
+
 job {
   id: "amd64-generic-asan"
   realm: "cbb-jobs"
@@ -149,7 +149,7 @@
   schedule: "0 */3 * * *"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Informational"
     tags: "cbb_branch:main"
     tags: "cbb_config:amd64-generic-asan"
@@ -168,7 +168,7 @@
   schedule: "0 */3 * * *"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Informational"
     tags: "cbb_branch:main"
     tags: "cbb_config:amd64-generic-fuzzer"
@@ -187,7 +187,7 @@
   schedule: "0 */3 * * *"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Informational"
     tags: "cbb_branch:main"
     tags: "cbb_config:amd64-generic-fwupd-upstream"
@@ -206,7 +206,7 @@
   schedule: "0 */3 * * *"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Informational"
     tags: "cbb_branch:main"
     tags: "cbb_config:amd64-generic-msan-fuzzer"
@@ -225,7 +225,7 @@
   schedule: "0 */3 * * *"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Informational"
     tags: "cbb_branch:main"
     tags: "cbb_config:amd64-generic-ubsan"
@@ -244,7 +244,7 @@
   schedule: "0 */3 * * *"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Informational"
     tags: "cbb_branch:main"
     tags: "cbb_config:amd64-generic-ubsan-fuzzer"
@@ -263,7 +263,7 @@
   schedule: "0 15 * * *"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Informational"
     tags: "cbb_branch:main"
     tags: "cbb_config:betty-vmtest-informational"
@@ -282,7 +282,7 @@
   schedule: "triggered"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Infra"
     tags: "cbb_branch:main"
     tags: "cbb_config:chromeos-infra-go"
@@ -301,7 +301,7 @@
   schedule: "with 30m interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Full"
     tags: "cbb_branch:main"
     tags: "cbb_config:chromiumos-sdk"
@@ -320,7 +320,7 @@
   schedule: "0 8 * * *"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Full"
     tags: "cbb_branch:main"
     tags: "cbb_config:chromiumos-sdk-llvm-next"
@@ -339,7 +339,7 @@
   schedule: "@hourly"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Infra"
     tags: "cbb_branch:main"
     tags: "cbb_config:config-updater"
@@ -358,7 +358,7 @@
   schedule: "with 168h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-ambassador-14265.B-buildspec"
@@ -379,7 +379,7 @@
   schedule: "with 168h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-asurada-13929.B-buildspec"
@@ -400,7 +400,7 @@
   schedule: "with 168h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-atlas-11907.B-buildspec"
@@ -421,7 +421,7 @@
   schedule: "with 720h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-auron-6459.B-buildspec"
@@ -442,7 +442,7 @@
   schedule: "with 720h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-auron-6772.B-buildspec"
@@ -457,13 +457,55 @@
 }
 
 job {
+  id: "factory-brya-14517.B-buildspec"
+  realm: "cbb-jobs"
+  acl_sets: "default"
+  schedule: "with 24h interval"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "general"
+    builder: "Factory"
+    tags: "cbb_branch:main"
+    tags: "cbb_config:factory-brya-14517.B-buildspec"
+    tags: "cbb_display_label:factory"
+    tags: "cbb_workspace_branch:factory-brya-14517.B"
+    properties: "cbb_branch:main"
+    properties: "cbb_config:factory-brya-14517.B-buildspec"
+    properties: "cbb_display_label:factory"
+    properties: "cbb_workspace_branch:factory-brya-14517.B"
+    properties: "cbb_extra_args:[\"--buildbot\"]"
+  }
+}
+
+job {
+  id: "factory-cherry-14455.B-buildspec"
+  realm: "cbb-jobs"
+  acl_sets: "default"
+  schedule: "with 168h interval"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "general"
+    builder: "Factory"
+    tags: "cbb_branch:main"
+    tags: "cbb_config:factory-cherry-14455.B-buildspec"
+    tags: "cbb_display_label:factory"
+    tags: "cbb_workspace_branch:factory-cherry-14455.B"
+    properties: "cbb_branch:main"
+    properties: "cbb_config:factory-cherry-14455.B-buildspec"
+    properties: "cbb_display_label:factory"
+    properties: "cbb_workspace_branch:factory-cherry-14455.B"
+    properties: "cbb_extra_args:[\"--buildbot\"]"
+  }
+}
+
+job {
   id: "factory-coral-10122.B-buildspec"
   realm: "cbb-jobs"
   acl_sets: "default"
   schedule: "with 720h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-coral-10122.B-buildspec"
@@ -481,10 +523,10 @@
   id: "factory-dedede-13683.B-buildspec"
   realm: "cbb-jobs"
   acl_sets: "default"
-  schedule: "with 24h interval"
+  schedule: "with 168h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-dedede-13683.B-buildspec"
@@ -505,7 +547,7 @@
   schedule: "with 168h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-drallion-13080.B-buildspec"
@@ -526,7 +568,7 @@
   schedule: "with 24h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-endeavour-13295.B-buildspec"
@@ -547,7 +589,7 @@
   schedule: "with 720h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-eve-9667.B-buildspec"
@@ -568,7 +610,7 @@
   schedule: "with 168h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-excelsior-12812.B-buildspec"
@@ -589,7 +631,7 @@
   schedule: "with 720h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-fizz-10167.B-buildspec"
@@ -610,7 +652,7 @@
   schedule: "with 720h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-gale-8743.19.B-buildspec"
@@ -631,7 +673,7 @@
   schedule: "with 720h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-glados-7657.B-buildspec"
@@ -652,7 +694,7 @@
   schedule: "with 720h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-glados-7828.B-buildspec"
@@ -673,7 +715,7 @@
   schedule: "with 720h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-gru-8652.B-buildspec"
@@ -694,7 +736,7 @@
   schedule: "with 720h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-gru-9017.B-buildspec"
@@ -715,7 +757,7 @@
   schedule: "with 720h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-grunt-11164.135.B-buildspec"
@@ -736,7 +778,7 @@
   schedule: "with 720h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-grunt-11164.B-buildspec"
@@ -757,7 +799,7 @@
   schedule: "with 168h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-hatch-12692.B-buildspec"
@@ -778,7 +820,7 @@
   schedule: "with 24h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-keeby-14162.B-buildspec"
@@ -799,7 +841,7 @@
   schedule: "with 168h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-kukui-12587.B-buildspec"
@@ -814,13 +856,34 @@
 }
 
 job {
+  id: "factory-kukui-14374.B-buildspec"
+  realm: "cbb-jobs"
+  acl_sets: "default"
+  schedule: "with 24h interval"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "general"
+    builder: "Factory"
+    tags: "cbb_branch:main"
+    tags: "cbb_config:factory-kukui-14374.B-buildspec"
+    tags: "cbb_display_label:factory"
+    tags: "cbb_workspace_branch:factory-kukui-14374.B"
+    properties: "cbb_branch:main"
+    properties: "cbb_config:factory-kukui-14374.B-buildspec"
+    properties: "cbb_display_label:factory"
+    properties: "cbb_workspace_branch:factory-kukui-14374.B"
+    properties: "cbb_extra_args:[\"--buildbot\"]"
+  }
+}
+
+job {
   id: "factory-mistral-12361.B-buildspec"
   realm: "cbb-jobs"
   acl_sets: "default"
   schedule: "with 168h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-mistral-12361.B-buildspec"
@@ -841,7 +904,7 @@
   schedule: "with 720h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-nami-10715.B-buildspec"
@@ -862,7 +925,7 @@
   schedule: "with 720h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-nocturne-11066.B-buildspec"
@@ -883,7 +946,7 @@
   schedule: "with 720h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-oak-8182.B-buildspec"
@@ -904,7 +967,7 @@
   schedule: "with 168h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-octopus-11512.B-buildspec"
@@ -925,7 +988,7 @@
   schedule: "with 720h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-poppy-10504.B-buildspec"
@@ -946,7 +1009,7 @@
   schedule: "with 168h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-puff-13329.B-buildspec"
@@ -967,7 +1030,7 @@
   schedule: "with 168h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-puff-13813.B-buildspec"
@@ -988,7 +1051,7 @@
   schedule: "with 720h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-rambi-5517.B-buildspec"
@@ -1009,7 +1072,7 @@
   schedule: "with 720h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-rambi-6420.B-buildspec"
@@ -1030,7 +1093,7 @@
   schedule: "with 720h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-rammus-11289.B-buildspec"
@@ -1051,7 +1114,7 @@
   schedule: "with 720h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-reef-8811.B-buildspec"
@@ -1072,7 +1135,7 @@
   schedule: "with 168h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-sarien-12033.B-buildspec"
@@ -1093,7 +1156,7 @@
   schedule: "with 720h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-scarlet-10211.B-buildspec"
@@ -1114,7 +1177,7 @@
   schedule: "with 720h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-soraka-10323.39.B-buildspec"
@@ -1135,7 +1198,7 @@
   schedule: "with 720h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-strago-7458.B-buildspec"
@@ -1156,7 +1219,7 @@
   schedule: "with 24h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-strongbad-13963.B-buildspec"
@@ -1177,7 +1240,7 @@
   schedule: "with 168h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-trogdor-13443.B-buildspec"
@@ -1198,7 +1261,7 @@
   schedule: "with 720h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-veyron-7505.B-buildspec"
@@ -1219,7 +1282,7 @@
   schedule: "with 168h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-volteer-13600.B-buildspec"
@@ -1240,7 +1303,7 @@
   schedule: "with 168h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-zork-13427.B-buildspec"
@@ -1261,7 +1324,7 @@
   schedule: "with 168h interval"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Factory"
     tags: "cbb_branch:main"
     tags: "cbb_config:factory-zork-13700.B-buildspec"
@@ -1282,7 +1345,7 @@
   schedule: "triggered"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Infra"
     tags: "cbb_branch:main"
     tags: "cbb_config:luci-scheduler-updater"
@@ -1301,7 +1364,7 @@
   schedule: "0 */3 * * *"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "Full"
     tags: "cbb_branch:main"
     tags: "cbb_config:master-full"
@@ -1314,51 +1377,13 @@
 }
 
 job {
-  id: "master-incremental"
-  realm: "cbb-jobs"
-  acl_sets: "default"
-  schedule: "with 10m interval"
-  buildbucket: {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
-    builder: "Incremental"
-    tags: "cbb_branch:main"
-    tags: "cbb_config:master-incremental"
-    tags: "cbb_display_label:incremental"
-    properties: "cbb_branch:main"
-    properties: "cbb_config:master-incremental"
-    properties: "cbb_display_label:incremental"
-    properties: "cbb_extra_args:[\"--buildbot\"]"
-  }
-}
-
-job {
-  id: "master-pi-android-pfq"
-  realm: "cbb-jobs"
-  acl_sets: "default"
-  schedule: "with 60m interval"
-  buildbucket: {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
-    builder: "PFQ"
-    tags: "cbb_branch:main"
-    tags: "cbb_config:master-pi-android-pfq"
-    tags: "cbb_display_label:pi_android_pfq"
-    properties: "cbb_branch:main"
-    properties: "cbb_config:master-pi-android-pfq"
-    properties: "cbb_display_label:pi_android_pfq"
-    properties: "cbb_extra_args:[\"--buildbot\"]"
-  }
-}
-
-job {
   id: "master-release"
   realm: "cbb-jobs"
   acl_sets: "default"
   schedule: "  0 2,10,18 * * *"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "LegacyRelease"
     tags: "cbb_branch:main"
     tags: "cbb_config:master-release"
@@ -1377,7 +1402,7 @@
   schedule: "30 */2 * * * *"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "LegacyRelease"
     tags: "cbb_branch:main"
     tags: "cbb_config:master-release-basic"
@@ -1390,58 +1415,172 @@
 }
 
 job {
-  id: "master-vmrvc-android-pfq"
+  id: "release-R100-14526.B-master-release"
   realm: "cbb-jobs"
   acl_sets: "default"
-  schedule: "with 60m interval"
+  schedule: "triggered"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
-    builder: "PFQ"
-    tags: "cbb_branch:main"
-    tags: "cbb_config:master-vmrvc-android-pfq"
-    tags: "cbb_display_label:vmrvc_android_pfq"
-    properties: "cbb_branch:main"
-    properties: "cbb_config:master-vmrvc-android-pfq"
-    properties: "cbb_display_label:vmrvc_android_pfq"
+    bucket: "general"
+    builder: "LegacyRelease"
+    tags: "cbb_branch:release-R100-14526.B"
+    tags: "cbb_config:master-release"
+    tags: "cbb_display_label:release"
+    properties: "cbb_branch:release-R100-14526.B"
+    properties: "cbb_config:master-release"
+    properties: "cbb_display_label:release"
     properties: "cbb_extra_args:[\"--buildbot\"]"
   }
 }
 
 job {
-  id: "master-vmsc-android-pfq"
+  id: "release-R100-14526.B-kevin-android-pi-pre-flight-branch"
   realm: "cbb-jobs"
   acl_sets: "default"
-  schedule: "with 60m interval"
+  schedule: "0 3,7,11,15,19,23 * * *"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
-    builder: "PFQ"
-    tags: "cbb_branch:main"
-    tags: "cbb_config:master-vmsc-android-pfq"
-    tags: "cbb_display_label:vmsc_android_pfq"
-    properties: "cbb_branch:main"
-    properties: "cbb_config:master-vmsc-android-pfq"
-    properties: "cbb_display_label:vmsc_android_pfq"
+    bucket: "general"
+    builder: "LegacyRelease"
+    tags: "cbb_branch:release-R100-14526.B"
+    tags: "cbb_config:kevin-android-pi-pre-flight-branch"
+    tags: "cbb_display_label:release"
+    properties: "cbb_branch:release-R100-14526.B"
+    properties: "cbb_config:kevin-android-pi-pre-flight-branch"
+    properties: "cbb_display_label:release"
     properties: "cbb_extra_args:[\"--buildbot\"]"
   }
 }
 
 job {
-  id: "master-vmt-android-pfq"
+  id: "release-R100-14526.B-hatch-android-rvc-pre-flight-branch"
   realm: "cbb-jobs"
   acl_sets: "default"
-  schedule: "with 150m interval"
+  schedule: "0 3,7,11,15,19,23 * * *"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
-    builder: "PFQ"
-    tags: "cbb_branch:main"
-    tags: "cbb_config:master-vmt-android-pfq"
-    tags: "cbb_display_label:vmt_android_pfq"
-    properties: "cbb_branch:main"
-    properties: "cbb_config:master-vmt-android-pfq"
-    properties: "cbb_display_label:vmt_android_pfq"
+    bucket: "general"
+    builder: "LegacyRelease"
+    tags: "cbb_branch:release-R100-14526.B"
+    tags: "cbb_config:hatch-android-rvc-pre-flight-branch"
+    tags: "cbb_display_label:release"
+    properties: "cbb_branch:release-R100-14526.B"
+    properties: "cbb_config:hatch-android-rvc-pre-flight-branch"
+    properties: "cbb_display_label:release"
+    properties: "cbb_extra_args:[\"--buildbot\"]"
+  }
+}
+
+job {
+  id: "release-R99-14469.B-master-release"
+  realm: "cbb-jobs"
+  acl_sets: "default"
+  schedule: "triggered"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "general"
+    builder: "LegacyRelease"
+    tags: "cbb_branch:release-R99-14469.B"
+    tags: "cbb_config:master-release"
+    tags: "cbb_display_label:release"
+    properties: "cbb_branch:release-R99-14469.B"
+    properties: "cbb_config:master-release"
+    properties: "cbb_display_label:release"
+    properties: "cbb_extra_args:[\"--buildbot\"]"
+  }
+}
+
+job {
+  id: "release-R99-14469.B-kevin-android-pi-pre-flight-branch"
+  realm: "cbb-jobs"
+  acl_sets: "default"
+  schedule: "0 2,6,10,14,18,22 * * *"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "general"
+    builder: "LegacyRelease"
+    tags: "cbb_branch:release-R99-14469.B"
+    tags: "cbb_config:kevin-android-pi-pre-flight-branch"
+    tags: "cbb_display_label:release"
+    properties: "cbb_branch:release-R99-14469.B"
+    properties: "cbb_config:kevin-android-pi-pre-flight-branch"
+    properties: "cbb_display_label:release"
+    properties: "cbb_extra_args:[\"--buildbot\"]"
+  }
+}
+
+job {
+  id: "release-R99-14469.B-hatch-android-rvc-pre-flight-branch"
+  realm: "cbb-jobs"
+  acl_sets: "default"
+  schedule: "0 2,6,10,14,18,22 * * *"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "general"
+    builder: "LegacyRelease"
+    tags: "cbb_branch:release-R99-14469.B"
+    tags: "cbb_config:hatch-android-rvc-pre-flight-branch"
+    tags: "cbb_display_label:release"
+    properties: "cbb_branch:release-R99-14469.B"
+    properties: "cbb_config:hatch-android-rvc-pre-flight-branch"
+    properties: "cbb_display_label:release"
+    properties: "cbb_extra_args:[\"--buildbot\"]"
+  }
+}
+
+job {
+  id: "release-R98-14388.B-master-release"
+  realm: "cbb-jobs"
+  acl_sets: "default"
+  schedule: "triggered"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "general"
+    builder: "LegacyRelease"
+    tags: "cbb_branch:release-R98-14388.B"
+    tags: "cbb_config:master-release"
+    tags: "cbb_display_label:release"
+    properties: "cbb_branch:release-R98-14388.B"
+    properties: "cbb_config:master-release"
+    properties: "cbb_display_label:release"
+    properties: "cbb_extra_args:[\"--buildbot\"]"
+  }
+}
+
+job {
+  id: "release-R98-14388.B-kevin-android-pi-pre-flight-branch"
+  realm: "cbb-jobs"
+  acl_sets: "default"
+  schedule: "0 2,6,10,14,18,22 * * *"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "general"
+    builder: "LegacyRelease"
+    tags: "cbb_branch:release-R98-14388.B"
+    tags: "cbb_config:kevin-android-pi-pre-flight-branch"
+    tags: "cbb_display_label:release"
+    properties: "cbb_branch:release-R98-14388.B"
+    properties: "cbb_config:kevin-android-pi-pre-flight-branch"
+    properties: "cbb_display_label:release"
+    properties: "cbb_extra_args:[\"--buildbot\"]"
+  }
+}
+
+job {
+  id: "release-R98-14388.B-hatch-android-rvc-pre-flight-branch"
+  realm: "cbb-jobs"
+  acl_sets: "default"
+  schedule: "0 2,6,10,14,18,22 * * *"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "general"
+    builder: "LegacyRelease"
+    tags: "cbb_branch:release-R98-14388.B"
+    tags: "cbb_config:hatch-android-rvc-pre-flight-branch"
+    tags: "cbb_display_label:release"
+    properties: "cbb_branch:release-R98-14388.B"
+    properties: "cbb_config:hatch-android-rvc-pre-flight-branch"
+    properties: "cbb_display_label:release"
     properties: "cbb_extra_args:[\"--buildbot\"]"
   }
 }
@@ -1453,8 +1592,8 @@
   schedule: "triggered"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
-    builder: "LegacyRelease"
+    bucket: "general"
+    builder: "LTSRelease"
     tags: "cbb_branch:release-R96-14268.B"
     tags: "cbb_config:master-release"
     tags: "cbb_display_label:release"
@@ -1469,11 +1608,11 @@
   id: "release-R96-14268.B-kevin-android-pi-pre-flight-branch"
   realm: "cbb-jobs"
   acl_sets: "default"
-  schedule: "0 3,7,11,15,19,23 * * *"
+  schedule: "0 2,6,10,14,18,22 * * *"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
-    builder: "LegacyRelease"
+    bucket: "general"
+    builder: "LTSRelease"
     tags: "cbb_branch:release-R96-14268.B"
     tags: "cbb_config:kevin-android-pi-pre-flight-branch"
     tags: "cbb_display_label:release"
@@ -1488,11 +1627,11 @@
   id: "release-R96-14268.B-hatch-android-rvc-pre-flight-branch"
   realm: "cbb-jobs"
   acl_sets: "default"
-  schedule: "0 3,7,11,15,19,23 * * *"
+  schedule: "0 2,6,10,14,18,22 * * *"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
-    builder: "LegacyRelease"
+    bucket: "general"
+    builder: "LTSRelease"
     tags: "cbb_branch:release-R96-14268.B"
     tags: "cbb_config:hatch-android-rvc-pre-flight-branch"
     tags: "cbb_display_label:release"
@@ -1504,189 +1643,18 @@
 }
 
 job {
-  id: "release-R94-14150.B-master-release"
+  id: "release-R96-14268.B-chell-chrome-no-afdo-uprev-pre-flight-branch"
   realm: "cbb-jobs"
   acl_sets: "default"
   schedule: "triggered"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
-    builder: "LegacyRelease"
-    tags: "cbb_branch:release-R94-14150.B"
-    tags: "cbb_config:master-release"
-    tags: "cbb_display_label:release"
-    properties: "cbb_branch:release-R94-14150.B"
-    properties: "cbb_config:master-release"
-    properties: "cbb_display_label:release"
-    properties: "cbb_extra_args:[\"--buildbot\"]"
-  }
-}
-
-job {
-  id: "release-R94-14150.B-kevin-android-pi-pre-flight-branch"
-  realm: "cbb-jobs"
-  acl_sets: "default"
-  schedule: "0 2,6,10,14,18,22 * * *"
-  buildbucket: {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
-    builder: "LegacyRelease"
-    tags: "cbb_branch:release-R94-14150.B"
-    tags: "cbb_config:kevin-android-pi-pre-flight-branch"
-    tags: "cbb_display_label:release"
-    properties: "cbb_branch:release-R94-14150.B"
-    properties: "cbb_config:kevin-android-pi-pre-flight-branch"
-    properties: "cbb_display_label:release"
-    properties: "cbb_extra_args:[\"--buildbot\"]"
-  }
-}
-
-job {
-  id: "release-R94-14150.B-hatch-android-rvc-pre-flight-branch"
-  realm: "cbb-jobs"
-  acl_sets: "default"
-  schedule: "0 2,6,10,14,18,22 * * *"
-  buildbucket: {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
-    builder: "LegacyRelease"
-    tags: "cbb_branch:release-R94-14150.B"
-    tags: "cbb_config:hatch-android-rvc-pre-flight-branch"
-    tags: "cbb_display_label:release"
-    properties: "cbb_branch:release-R94-14150.B"
-    properties: "cbb_config:hatch-android-rvc-pre-flight-branch"
-    properties: "cbb_display_label:release"
-    properties: "cbb_extra_args:[\"--buildbot\"]"
-  }
-}
-
-job {
-  id: "release-R93-14092.B-master-release"
-  realm: "cbb-jobs"
-  acl_sets: "default"
-  schedule: "triggered"
-  buildbucket: {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
-    builder: "LegacyRelease"
-    tags: "cbb_branch:release-R93-14092.B"
-    tags: "cbb_config:master-release"
-    tags: "cbb_display_label:release"
-    properties: "cbb_branch:release-R93-14092.B"
-    properties: "cbb_config:master-release"
-    properties: "cbb_display_label:release"
-    properties: "cbb_extra_args:[\"--buildbot\"]"
-  }
-}
-
-job {
-  id: "release-R93-14092.B-kevin-android-pi-pre-flight-branch"
-  realm: "cbb-jobs"
-  acl_sets: "default"
-  schedule: "0 2,6,10,14,18,22 * * *"
-  buildbucket: {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
-    builder: "LegacyRelease"
-    tags: "cbb_branch:release-R93-14092.B"
-    tags: "cbb_config:kevin-android-pi-pre-flight-branch"
-    tags: "cbb_display_label:release"
-    properties: "cbb_branch:release-R93-14092.B"
-    properties: "cbb_config:kevin-android-pi-pre-flight-branch"
-    properties: "cbb_display_label:release"
-    properties: "cbb_extra_args:[\"--buildbot\"]"
-  }
-}
-
-job {
-  id: "release-R93-14092.B-hatch-android-rvc-pre-flight-branch"
-  realm: "cbb-jobs"
-  acl_sets: "default"
-  schedule: "0 2,6,10,14,18,22 * * *"
-  buildbucket: {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
-    builder: "LegacyRelease"
-    tags: "cbb_branch:release-R93-14092.B"
-    tags: "cbb_config:hatch-android-rvc-pre-flight-branch"
-    tags: "cbb_display_label:release"
-    properties: "cbb_branch:release-R93-14092.B"
-    properties: "cbb_config:hatch-android-rvc-pre-flight-branch"
-    properties: "cbb_display_label:release"
-    properties: "cbb_extra_args:[\"--buildbot\"]"
-  }
-}
-
-job {
-  id: "release-R90-13816.B-master-release"
-  realm: "cbb-jobs"
-  acl_sets: "default"
-  schedule: "triggered"
-  buildbucket: {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "LTSRelease"
-    tags: "cbb_branch:release-R90-13816.B"
-    tags: "cbb_config:master-release"
-    tags: "cbb_display_label:release"
-    properties: "cbb_branch:release-R90-13816.B"
-    properties: "cbb_config:master-release"
-    properties: "cbb_display_label:release"
-    properties: "cbb_extra_args:[\"--buildbot\"]"
-  }
-}
-
-job {
-  id: "release-R90-13816.B-kevin-android-pi-pre-flight-branch"
-  realm: "cbb-jobs"
-  acl_sets: "default"
-  schedule: "0 2,6,10,14,18,22 * * *"
-  buildbucket: {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
-    builder: "LTSRelease"
-    tags: "cbb_branch:release-R90-13816.B"
-    tags: "cbb_config:kevin-android-pi-pre-flight-branch"
-    tags: "cbb_display_label:release"
-    properties: "cbb_branch:release-R90-13816.B"
-    properties: "cbb_config:kevin-android-pi-pre-flight-branch"
-    properties: "cbb_display_label:release"
-    properties: "cbb_extra_args:[\"--buildbot\"]"
-  }
-}
-
-job {
-  id: "release-R90-13816.B-hatch-android-rvc-pre-flight-branch"
-  realm: "cbb-jobs"
-  acl_sets: "default"
-  schedule: "0 2,6,10,14,18,22 * * *"
-  buildbucket: {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
-    builder: "LTSRelease"
-    tags: "cbb_branch:release-R90-13816.B"
-    tags: "cbb_config:hatch-android-rvc-pre-flight-branch"
-    tags: "cbb_display_label:release"
-    properties: "cbb_branch:release-R90-13816.B"
-    properties: "cbb_config:hatch-android-rvc-pre-flight-branch"
-    properties: "cbb_display_label:release"
-    properties: "cbb_extra_args:[\"--buildbot\"]"
-  }
-}
-
-job {
-  id: "release-R90-13816.B-chell-chrome-no-afdo-uprev-pre-flight-branch"
-  realm: "cbb-jobs"
-  acl_sets: "default"
-  schedule: "triggered"
-  buildbucket: {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
-    builder: "LTSRelease"
-    tags: "cbb_branch:release-R90-13816.B"
+    tags: "cbb_branch:release-R96-14268.B"
     tags: "cbb_config:chell-chrome-no-afdo-uprev-pre-flight-branch"
     tags: "cbb_display_label:release"
-    properties: "cbb_branch:release-R90-13816.B"
+    properties: "cbb_branch:release-R96-14268.B"
     properties: "cbb_config:chell-chrome-no-afdo-uprev-pre-flight-branch"
     properties: "cbb_display_label:release"
     properties: "cbb_extra_args:[\"--buildbot\"]"
@@ -1694,18 +1662,18 @@
 }
 
 job {
-  id: "release-R90-13816.B-orderfile-generate-toolchain"
+  id: "release-R96-14268.B-orderfile-generate-toolchain"
   realm: "cbb-jobs"
   acl_sets: "default"
   schedule: "0 8/12 * * *"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "LTSRelease"
-    tags: "cbb_branch:release-R90-13816.B"
+    tags: "cbb_branch:release-R96-14268.B"
     tags: "cbb_config:orderfile-generate-toolchain"
     tags: "cbb_display_label:release"
-    properties: "cbb_branch:release-R90-13816.B"
+    properties: "cbb_branch:release-R96-14268.B"
     properties: "cbb_config:orderfile-generate-toolchain"
     properties: "cbb_display_label:release"
     properties: "cbb_extra_args:[\"--buildbot\"]"
@@ -1713,18 +1681,18 @@
 }
 
 job {
-  id: "release-R90-13816.B-orderfile-verify-toolchain"
+  id: "release-R96-14268.B-orderfile-verify-toolchain"
   realm: "cbb-jobs"
   acl_sets: "default"
   schedule: "0 0/12 * * *"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "LTSRelease"
-    tags: "cbb_branch:release-R90-13816.B"
+    tags: "cbb_branch:release-R96-14268.B"
     tags: "cbb_config:orderfile-verify-toolchain"
     tags: "cbb_display_label:release"
-    properties: "cbb_branch:release-R90-13816.B"
+    properties: "cbb_branch:release-R96-14268.B"
     properties: "cbb_config:orderfile-verify-toolchain"
     properties: "cbb_display_label:release"
     properties: "cbb_extra_args:[\"--buildbot\"]"
@@ -1732,18 +1700,18 @@
 }
 
 job {
-  id: "release-R90-13816.B-benchmark-afdo-generate"
+  id: "release-R96-14268.B-benchmark-afdo-generate"
   realm: "cbb-jobs"
   acl_sets: "default"
   schedule: "0 8/12 * * *"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "LTSRelease"
-    tags: "cbb_branch:release-R90-13816.B"
+    tags: "cbb_branch:release-R96-14268.B"
     tags: "cbb_config:benchmark-afdo-generate"
     tags: "cbb_display_label:release"
-    properties: "cbb_branch:release-R90-13816.B"
+    properties: "cbb_branch:release-R96-14268.B"
     properties: "cbb_config:benchmark-afdo-generate"
     properties: "cbb_display_label:release"
     properties: "cbb_extra_args:[\"--buildbot\"]"
@@ -1751,18 +1719,18 @@
 }
 
 job {
-  id: "release-R90-13816.B-chrome-silvermont-release-afdo-verify"
+  id: "release-R96-14268.B-chrome-silvermont-release-afdo-verify"
   realm: "cbb-jobs"
   acl_sets: "default"
   schedule: "0 3/12 * * *"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "LTSRelease"
-    tags: "cbb_branch:release-R90-13816.B"
+    tags: "cbb_branch:release-R96-14268.B"
     tags: "cbb_config:chrome-silvermont-release-afdo-verify"
     tags: "cbb_display_label:release"
-    properties: "cbb_branch:release-R90-13816.B"
+    properties: "cbb_branch:release-R96-14268.B"
     properties: "cbb_config:chrome-silvermont-release-afdo-verify"
     properties: "cbb_display_label:release"
     properties: "cbb_extra_args:[\"--buildbot\"]"
@@ -1770,18 +1738,18 @@
 }
 
 job {
-  id: "release-R90-13816.B-chrome-airmont-release-afdo-verify"
+  id: "release-R96-14268.B-chrome-airmont-release-afdo-verify"
   realm: "cbb-jobs"
   acl_sets: "default"
   schedule: "0 3/12 * * *"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "LTSRelease"
-    tags: "cbb_branch:release-R90-13816.B"
+    tags: "cbb_branch:release-R96-14268.B"
     tags: "cbb_config:chrome-airmont-release-afdo-verify"
     tags: "cbb_display_label:release"
-    properties: "cbb_branch:release-R90-13816.B"
+    properties: "cbb_branch:release-R96-14268.B"
     properties: "cbb_config:chrome-airmont-release-afdo-verify"
     properties: "cbb_display_label:release"
     properties: "cbb_extra_args:[\"--buildbot\"]"
@@ -1789,18 +1757,18 @@
 }
 
 job {
-  id: "release-R90-13816.B-chrome-broadwell-release-afdo-verify"
+  id: "release-R96-14268.B-chrome-broadwell-release-afdo-verify"
   realm: "cbb-jobs"
   acl_sets: "default"
   schedule: "0 3/12 * * *"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "LTSRelease"
-    tags: "cbb_branch:release-R90-13816.B"
+    tags: "cbb_branch:release-R96-14268.B"
     tags: "cbb_config:chrome-broadwell-release-afdo-verify"
     tags: "cbb_display_label:release"
-    properties: "cbb_branch:release-R90-13816.B"
+    properties: "cbb_branch:release-R96-14268.B"
     properties: "cbb_config:chrome-broadwell-release-afdo-verify"
     properties: "cbb_display_label:release"
     properties: "cbb_extra_args:[\"--buildbot\"]"
diff --git a/config/waterfall_layout_dump.txt b/config/waterfall_layout_dump.txt
index 116a24c..9684690 100644
--- a/config/waterfall_layout_dump.txt
+++ b/config/waterfall_layout_dump.txt
@@ -16,6 +16,11 @@
     guado-factory-auron-6772.B-factorybranch
     rikku-factory-auron-6772.B-factorybranch
     tidus-factory-auron-6772.B-factorybranch
+  factory-brya-14517.B-buildspec
+    brask-factory-brya-14517.B-factorybranch
+    brya-factory-brya-14517.B-factorybranch
+  factory-cherry-14455.B-buildspec
+    cherry-factory-cherry-14455.B-factorybranch
   factory-coral-10122.B-buildspec
     coral-factory-coral-10122.B-factorybranch
   factory-dedede-13683.B-buildspec
@@ -60,6 +65,9 @@
   factory-kukui-12587.B-buildspec
     jacuzzi-factory-kukui-12587.B-factorybranch
     kukui-factory-kukui-12587.B-factorybranch
+  factory-kukui-14374.B-buildspec
+    jacuzzi-factory-kukui-14374.B-factorybranch
+    kukui-factory-kukui-14374.B-factorybranch
   factory-mistral-12361.B-buildspec
     mistral-factory-mistral-12361.B-factorybranch
   factory-nami-10715.B-buildspec
@@ -127,7 +135,6 @@
     trogdor-factory-trogdor-13443.B-factorybranch
   factory-veyron-7505.B-buildspec
     veyron_fievel-factory-veyron-7505.B-factorybranch
-    veyron_rialto-factory-veyron-7505.B-factorybranch
     veyron_tiger-factory-veyron-7505.B-factorybranch
   factory-volteer-13600.B-buildspec
     volteer-factory-volteer-13600.B-factorybranch
@@ -144,16 +151,13 @@
     arm64-generic-full
     eve-full
     hana-full
+    jacuzzi-full
     kevin-full
     kevin64-full
+    octopus-full
     tael-full
     tatl-full
-
-== incremental ==
-  master-incremental
-    amd64-generic-incremental
-    betty-incremental
-    chell-incremental
+    zork-full
 
 == informational ==
   amd64-generic-asan
@@ -164,14 +168,6 @@
   amd64-generic-ubsan-fuzzer
   betty-vmtest-informational
 
-== pi_android_pfq ==
-  master-pi-android-pfq
-    betty-pi-arc-pi-android-pfq
-    coral-pi-android-pfq
-    grunt-pi-android-pfq
-    kevin-pi-android-pfq
-    rammus-pi-android-pfq
-
 == release ==
   master-release
     adlrvp-release
@@ -179,7 +175,6 @@
     asuka-release
     asurada-connectivitynext-release
     asurada-release
-    asurada-zephyr-release
     atlas-blueznext-release
     atlas-connectivitynext-release
     atlas-kernelnext-release
@@ -188,7 +183,6 @@
     aurora-release
     banon-release
     beaglebone-release
-    beaglebone_servo-release
     betty-arc-r-release
     betty-arc-s-release
     betty-arc-t-release
@@ -197,11 +191,12 @@
     betty-release
     bob-release
     brask-release
+    brya-lvm-stateful-release
     brya-manatee-release
     brya-release
+    brya-zephyr-release
     bubs-release
     caroline-arc64-release
-    caroline-kernelnext-release
     caroline-ndktranslation-release
     caroline-release
     caroline-userdebug-release
@@ -209,10 +204,13 @@
     celes-release
     chell-release
     cherry-release
+    cherry64-release
     coral-kernelnext-release
     coral-release
+    corsola-release
     cyan-release
     dedede-release
+    draco-release
     drallion-release
     edgar-release
     elm-arc64-release
@@ -222,16 +220,15 @@
     endeavour-release
     eve-arc-r-release
     eve-arm64-release
-    eve-kernelnext-release
     eve-kvm-release
     eve-release
     eve-userdebug-release
     excelsior-release
     fizz-cfm-release
+    fizz-kernelnext-release
     fizz-labstation-release
     fizz-moblab-release
     fizz-release
-    gale-release
     goroh-release
     grunt-arc-r-release
     grunt-kernelnext-release
@@ -246,12 +243,12 @@
     hatch-arc-r-release
     hatch-arc-r-userdebug-release
     hatch-arc-s-release
+    hatch-arc-t-release
     hatch-blueznext-release
     hatch-borealis-release
     hatch-connectivitynext-release
     hatch-diskswap-release
     hatch-kernelnext-release
-    hatch-manatee-release
     hatch-release
     herobrine-release
     jacuzzi-kernelnext-release
@@ -270,7 +267,6 @@
     lars-kernelnext-release
     lars-release
     majolica-release
-    mistral-release
     mushu-release
     nami-kernelnext-release
     nami-release
@@ -301,15 +297,21 @@
     sand-release
     sarien-kernelnext-release
     sarien-release
+    scarlet-kernelnext-release
     scarlet-release
     senor-release
     sentry-release
     setzer-release
     shadowkeep-release
+    skolas-release
+    skyrim-chausie-release
+    skyrim-kernelnext-release
+    skyrim-release
     snappy-kernelnext-release
     snappy-release
     soraka-libcamera-release
     soraka-release
+    strongbad-kernelnext-release
     strongbad-release
     tael-release
     tatl-release
@@ -321,14 +323,10 @@
     trogdor-zephyr-release
     trogdor64-release
     ultima-release
-    veyron_fievel-release
-    veyron_rialto-release
-    veyron_tiger-release
     volteer-borealis-release
     volteer-kernelnext-release
     volteer-manatee-release
     volteer-release
-    volteer-zephyr-release
     wizpig-release
     zork-arc-r-release
     zork-borealis-release
@@ -349,24 +347,6 @@
   config-updater
   luci-scheduler-updater
 
-== vmrvc_android_pfq ==
-  master-vmrvc-android-pfq
-    eve-arc-r-vmrvc-android-pfq
-    grunt-arc-r-vmrvc-android-pfq
-    hatch-vmrvc-android-pfq
-    kukui-arc-r-vmrvc-android-pfq
-    rammus-arc-r-vmrvc-android-pfq
-    zork-arc-r-vmrvc-android-pfq
-
-== vmsc_android_pfq ==
-  master-vmsc-android-pfq
-    betty-arc-s-vmsc-android-pfq
-    hatch-arc-s-vmsc-android-pfq
-
-== vmt_android_pfq ==
-  master-vmt-android-pfq
-    betty-arc-t-vmt-android-pfq
-
 == tryjob ==
   adlrvp-full-tryjob
   adlrvp-llvm-next-toolchain-tryjob
@@ -386,7 +366,6 @@
   amd64-generic-full-tryjob
   amd64-generic-fuzzer-tryjob
   amd64-generic-fwupd-upstream-tryjob
-  amd64-generic-incremental-tryjob
   amd64-generic-llvm-next-toolchain-tryjob
   amd64-generic-llvm-toolchain-tryjob
   amd64-generic-msan-fuzzer-tryjob
@@ -432,12 +411,6 @@
   asurada-payloads-tryjob
   asurada-release-tryjob
   asurada-unittest-stress
-  asurada-zephyr-full-tryjob
-  asurada-zephyr-llvm-next-toolchain-tryjob
-  asurada-zephyr-llvm-toolchain-tryjob
-  asurada-zephyr-payloads-tryjob
-  asurada-zephyr-release-tryjob
-  asurada-zephyr-unittest-stress
   atlas-blueznext-full-tryjob
   atlas-blueznext-llvm-next-toolchain-tryjob
   atlas-blueznext-llvm-toolchain-tryjob
@@ -488,7 +461,6 @@
   banon-release-tryjob
   banon-unittest-stress
   beaglebone-full-tryjob
-  beaglebone-incremental-tryjob
   beaglebone-llvm-next-toolchain-tryjob
   beaglebone-llvm-toolchain-tryjob
   beaglebone-release-tryjob
@@ -498,7 +470,6 @@
   beaglebone_servo-llvm-toolchain-tryjob
   beaglebone_servo-release-tryjob
   beaglebone_servo-unittest-stress
-  benchmark-afdo-generate-tryjob
   betty-arc-r-full-tryjob
   betty-arc-r-llvm-next-toolchain-tryjob
   betty-arc-r-llvm-toolchain-tryjob
@@ -511,17 +482,14 @@
   betty-arc-s-payloads-tryjob
   betty-arc-s-release-tryjob
   betty-arc-s-unittest-stress
-  betty-arc-s-vmsc-android-pfq-tryjob
   betty-arc-t-full-tryjob
   betty-arc-t-llvm-next-toolchain-tryjob
   betty-arc-t-llvm-toolchain-tryjob
   betty-arc-t-payloads-tryjob
   betty-arc-t-release-tryjob
   betty-arc-t-unittest-stress
-  betty-arc-t-vmt-android-pfq-tryjob
   betty-asan-tryjob
   betty-full-tryjob
-  betty-incremental-tryjob
   betty-kernelnext-full-tryjob
   betty-kernelnext-llvm-next-toolchain-tryjob
   betty-kernelnext-llvm-toolchain-tryjob
@@ -535,7 +503,6 @@
   betty-pi-arc-llvm-next-toolchain-tryjob
   betty-pi-arc-llvm-toolchain-tryjob
   betty-pi-arc-payloads-tryjob
-  betty-pi-arc-pi-android-pfq-tryjob
   betty-pi-arc-release-tryjob
   betty-pi-arc-unittest-stress
   betty-release-tryjob
@@ -548,15 +515,23 @@
   bob-payloads-tryjob
   bob-release-tryjob
   bob-unittest-stress
+  brask-factory-brya-14517.B-factorybranch-tryjob
   brask-full-tryjob
   brask-llvm-next-toolchain-tryjob
   brask-llvm-toolchain-tryjob
   brask-payloads-tryjob
   brask-release-tryjob
   brask-unittest-stress
+  brya-factory-brya-14517.B-factorybranch-tryjob
   brya-full-tryjob
   brya-llvm-next-toolchain-tryjob
   brya-llvm-toolchain-tryjob
+  brya-lvm-stateful-full-tryjob
+  brya-lvm-stateful-llvm-next-toolchain-tryjob
+  brya-lvm-stateful-llvm-toolchain-tryjob
+  brya-lvm-stateful-payloads-tryjob
+  brya-lvm-stateful-release-tryjob
+  brya-lvm-stateful-unittest-stress
   brya-manatee-full-tryjob
   brya-manatee-llvm-next-toolchain-tryjob
   brya-manatee-llvm-toolchain-tryjob
@@ -566,6 +541,12 @@
   brya-payloads-tryjob
   brya-release-tryjob
   brya-unittest-stress
+  brya-zephyr-full-tryjob
+  brya-zephyr-llvm-next-toolchain-tryjob
+  brya-zephyr-llvm-toolchain-tryjob
+  brya-zephyr-payloads-tryjob
+  brya-zephyr-release-tryjob
+  brya-zephyr-unittest-stress
   bubs-full-tryjob
   bubs-llvm-next-toolchain-tryjob
   bubs-llvm-toolchain-tryjob
@@ -583,12 +564,6 @@
   caroline-arc64-unittest-stress
   caroline-factory-glados-7828.B-factorybranch-tryjob
   caroline-full-tryjob
-  caroline-kernelnext-full-tryjob
-  caroline-kernelnext-llvm-next-toolchain-tryjob
-  caroline-kernelnext-llvm-toolchain-tryjob
-  caroline-kernelnext-payloads-tryjob
-  caroline-kernelnext-release-tryjob
-  caroline-kernelnext-unittest-stress
   caroline-llvm-next-toolchain-tryjob
   caroline-llvm-toolchain-tryjob
   caroline-ndktranslation-full-tryjob
@@ -624,21 +599,24 @@
   chell-factory-glados-7657.B-factorybranch-tryjob
   chell-factory-glados-7828.B-factorybranch-tryjob
   chell-full-tryjob
-  chell-incremental-tryjob
   chell-llvm-next-toolchain-tryjob
   chell-llvm-toolchain-tryjob
   chell-payloads-tryjob
   chell-release-tryjob
   chell-unittest-stress
+  cherry-factory-cherry-14455.B-factorybranch-tryjob
   cherry-full-tryjob
   cherry-llvm-next-toolchain-tryjob
   cherry-llvm-toolchain-tryjob
   cherry-payloads-tryjob
   cherry-release-tryjob
   cherry-unittest-stress
-  chrome-airmont-release-afdo-verify-tryjob
-  chrome-broadwell-release-afdo-verify-tryjob
-  chrome-silvermont-release-afdo-verify-tryjob
+  cherry64-full-tryjob
+  cherry64-llvm-next-toolchain-tryjob
+  cherry64-llvm-toolchain-tryjob
+  cherry64-payloads-tryjob
+  cherry64-release-tryjob
+  cherry64-unittest-stress
   chromeos-infra-go-tryjob
   chromiumos-sdk-llvm-next-tryjob
   chromiumos-sdk-tryjob
@@ -655,9 +633,14 @@
   coral-llvm-toolchain-tryjob
   coral-master-factorybranch-tryjob
   coral-payloads-tryjob
-  coral-pi-android-pfq-tryjob
   coral-release-tryjob
   coral-unittest-stress
+  corsola-full-tryjob
+  corsola-llvm-next-toolchain-tryjob
+  corsola-llvm-toolchain-tryjob
+  corsola-payloads-tryjob
+  corsola-release-tryjob
+  corsola-unittest-stress
   cyan-factory-strago-7458.B-factorybranch-tryjob
   cyan-full-tryjob
   cyan-llvm-next-toolchain-tryjob
@@ -678,6 +661,12 @@
   deltaur-payloads-tryjob
   deltaur-release-tryjob
   deltaur-unittest-stress
+  draco-full-tryjob
+  draco-llvm-next-toolchain-tryjob
+  draco-llvm-toolchain-tryjob
+  draco-payloads-tryjob
+  draco-release-tryjob
+  draco-unittest-stress
   drallion-factory-drallion-13080.B-factorybranch-tryjob
   drallion-full-tryjob
   drallion-llvm-next-toolchain-tryjob
@@ -733,7 +722,6 @@
   eve-arc-r-payloads-tryjob
   eve-arc-r-release-tryjob
   eve-arc-r-unittest-stress
-  eve-arc-r-vmrvc-android-pfq-tryjob
   eve-arm64-full-tryjob
   eve-arm64-llvm-next-toolchain-tryjob
   eve-arm64-llvm-toolchain-tryjob
@@ -742,12 +730,6 @@
   eve-arm64-unittest-stress
   eve-factory-eve-9667.B-factorybranch-tryjob
   eve-full-tryjob
-  eve-kernelnext-full-tryjob
-  eve-kernelnext-llvm-next-toolchain-tryjob
-  eve-kernelnext-llvm-toolchain-tryjob
-  eve-kernelnext-payloads-tryjob
-  eve-kernelnext-release-tryjob
-  eve-kernelnext-unittest-stress
   eve-kvm-full-tryjob
   eve-kvm-llvm-next-toolchain-tryjob
   eve-kvm-llvm-toolchain-tryjob
@@ -793,6 +775,11 @@
     guado-factory-auron-6772.B-factorybranch-tryjob
     rikku-factory-auron-6772.B-factorybranch-tryjob
     tidus-factory-auron-6772.B-factorybranch-tryjob
+  factory-brya-14517.B-buildspec-tryjob
+    brask-factory-brya-14517.B-factorybranch-tryjob
+    brya-factory-brya-14517.B-factorybranch-tryjob
+  factory-cherry-14455.B-buildspec-tryjob
+    cherry-factory-cherry-14455.B-factorybranch-tryjob
   factory-coral-10122.B-buildspec-tryjob
     coral-factory-coral-10122.B-factorybranch-tryjob
   factory-dedede-13683.B-buildspec-tryjob
@@ -837,6 +824,9 @@
   factory-kukui-12587.B-buildspec-tryjob
     jacuzzi-factory-kukui-12587.B-factorybranch-tryjob
     kukui-factory-kukui-12587.B-factorybranch-tryjob
+  factory-kukui-14374.B-buildspec-tryjob
+    jacuzzi-factory-kukui-14374.B-factorybranch-tryjob
+    kukui-factory-kukui-14374.B-factorybranch-tryjob
   factory-mistral-12361.B-buildspec-tryjob
     mistral-factory-mistral-12361.B-factorybranch-tryjob
   factory-nami-10715.B-buildspec-tryjob
@@ -904,7 +894,6 @@
     trogdor-factory-trogdor-13443.B-factorybranch-tryjob
   factory-veyron-7505.B-buildspec-tryjob
     veyron_fievel-factory-veyron-7505.B-factorybranch-tryjob
-    veyron_rialto-factory-veyron-7505.B-factorybranch-tryjob
     veyron_tiger-factory-veyron-7505.B-factorybranch-tryjob
   factory-volteer-13600.B-buildspec-tryjob
     volteer-factory-volteer-13600.B-factorybranch-tryjob
@@ -928,6 +917,12 @@
   fizz-cfm-unittest-stress
   fizz-factory-fizz-10167.B-factorybranch-tryjob
   fizz-full-tryjob
+  fizz-kernelnext-full-tryjob
+  fizz-kernelnext-llvm-next-toolchain-tryjob
+  fizz-kernelnext-llvm-toolchain-tryjob
+  fizz-kernelnext-payloads-tryjob
+  fizz-kernelnext-release-tryjob
+  fizz-kernelnext-unittest-stress
   fizz-labstation-full-tryjob
   fizz-labstation-llvm-next-toolchain-tryjob
   fizz-labstation-llvm-toolchain-tryjob
@@ -976,7 +971,6 @@
   grunt-arc-r-payloads-tryjob
   grunt-arc-r-release-tryjob
   grunt-arc-r-unittest-stress
-  grunt-arc-r-vmrvc-android-pfq-tryjob
   grunt-factory-grunt-11164.135.B-factorybranch-tryjob
   grunt-factory-grunt-11164.B-factorybranch-tryjob
   grunt-full-tryjob
@@ -989,7 +983,6 @@
   grunt-llvm-next-toolchain-tryjob
   grunt-llvm-toolchain-tryjob
   grunt-payloads-tryjob
-  grunt-pi-android-pfq-tryjob
   grunt-release-basic-tryjob
   grunt-release-tryjob
   grunt-unittest-stress
@@ -1038,7 +1031,6 @@
   hatch-arc-r-ack-payloads-tryjob
   hatch-arc-r-ack-release-tryjob
   hatch-arc-r-ack-unittest-stress
-  hatch-arc-r-android-rvc-pre-flight-branch-tryjob
   hatch-arc-r-full-tryjob
   hatch-arc-r-llvm-next-toolchain-tryjob
   hatch-arc-r-llvm-toolchain-tryjob
@@ -1057,7 +1049,12 @@
   hatch-arc-s-payloads-tryjob
   hatch-arc-s-release-tryjob
   hatch-arc-s-unittest-stress
-  hatch-arc-s-vmsc-android-pfq-tryjob
+  hatch-arc-t-full-tryjob
+  hatch-arc-t-llvm-next-toolchain-tryjob
+  hatch-arc-t-llvm-toolchain-tryjob
+  hatch-arc-t-payloads-tryjob
+  hatch-arc-t-release-tryjob
+  hatch-arc-t-unittest-stress
   hatch-blueznext-full-tryjob
   hatch-blueznext-llvm-next-toolchain-tryjob
   hatch-blueznext-llvm-toolchain-tryjob
@@ -1092,16 +1089,9 @@
   hatch-kernelnext-unittest-stress
   hatch-llvm-next-toolchain-tryjob
   hatch-llvm-toolchain-tryjob
-  hatch-manatee-full-tryjob
-  hatch-manatee-llvm-next-toolchain-tryjob
-  hatch-manatee-llvm-toolchain-tryjob
-  hatch-manatee-payloads-tryjob
-  hatch-manatee-release-tryjob
-  hatch-manatee-unittest-stress
   hatch-payloads-tryjob
   hatch-release-tryjob
   hatch-unittest-stress
-  hatch-vmrvc-android-pfq-tryjob
   heli-factory-rambi-6420.B-factorybranch-tryjob
   herobrine-full-tryjob
   herobrine-llvm-next-toolchain-tryjob
@@ -1110,6 +1100,7 @@
   herobrine-release-tryjob
   herobrine-unittest-stress
   jacuzzi-factory-kukui-12587.B-factorybranch-tryjob
+  jacuzzi-factory-kukui-14374.B-factorybranch-tryjob
   jacuzzi-full-tryjob
   jacuzzi-kernelnext-full-tryjob
   jacuzzi-kernelnext-llvm-next-toolchain-tryjob
@@ -1155,10 +1146,6 @@
   kefka-payloads-tryjob
   kefka-release-tryjob
   kefka-unittest-stress
-  kernel-3_18-release-afdo-verify-tryjob
-  kernel-4_14-release-afdo-verify-tryjob
-  kernel-4_19-release-afdo-verify-tryjob
-  kernel-4_4-release-afdo-verify-tryjob
   kevin-android-pi-pre-flight-branch-tryjob
   kevin-factory-gru-8652.B-factorybranch-tryjob
   kevin-full-tryjob
@@ -1172,7 +1159,6 @@
   kevin-llvm-toolchain-tryjob
   kevin-llvm-tot-toolchain-tryjob
   kevin-payloads-tryjob
-  kevin-pi-android-pfq-tryjob
   kevin-release-tryjob
   kevin-unittest-stress
   kevin-userdebug-full-tryjob
@@ -1195,8 +1181,8 @@
   kukui-arc-r-payloads-tryjob
   kukui-arc-r-release-tryjob
   kukui-arc-r-unittest-stress
-  kukui-arc-r-vmrvc-android-pfq-tryjob
   kukui-factory-kukui-12587.B-factorybranch-tryjob
+  kukui-factory-kukui-14374.B-factorybranch-tryjob
   kukui-full-tryjob
   kukui-kernelnext-full-tryjob
   kukui-kernelnext-llvm-next-toolchain-tryjob
@@ -1258,20 +1244,13 @@
     arm64-generic-full-tryjob
     eve-full-tryjob
     hana-full-tryjob
+    jacuzzi-full-tryjob
     kevin-full-tryjob
     kevin64-full-tryjob
+    octopus-full-tryjob
     tael-full-tryjob
     tatl-full-tryjob
-  master-incremental-tryjob
-    amd64-generic-incremental-tryjob
-    betty-incremental-tryjob
-    chell-incremental-tryjob
-  master-pi-android-pfq-tryjob
-    betty-pi-arc-pi-android-pfq-tryjob
-    coral-pi-android-pfq-tryjob
-    grunt-pi-android-pfq-tryjob
-    kevin-pi-android-pfq-tryjob
-    rammus-pi-android-pfq-tryjob
+    zork-full-tryjob
   master-release-basic-tryjob
     atlas-release-basic-tryjob
     eve-release-basic-tryjob
@@ -1282,7 +1261,6 @@
     asuka-release-tryjob
     asurada-connectivitynext-release-tryjob
     asurada-release-tryjob
-    asurada-zephyr-release-tryjob
     atlas-blueznext-release-tryjob
     atlas-connectivitynext-release-tryjob
     atlas-kernelnext-release-tryjob
@@ -1291,7 +1269,6 @@
     aurora-release-tryjob
     banon-release-tryjob
     beaglebone-release-tryjob
-    beaglebone_servo-release-tryjob
     betty-arc-r-release-tryjob
     betty-arc-s-release-tryjob
     betty-arc-t-release-tryjob
@@ -1300,11 +1277,12 @@
     betty-release-tryjob
     bob-release-tryjob
     brask-release-tryjob
+    brya-lvm-stateful-release-tryjob
     brya-manatee-release-tryjob
     brya-release-tryjob
+    brya-zephyr-release-tryjob
     bubs-release-tryjob
     caroline-arc64-release-tryjob
-    caroline-kernelnext-release-tryjob
     caroline-ndktranslation-release-tryjob
     caroline-release-tryjob
     caroline-userdebug-release-tryjob
@@ -1312,10 +1290,13 @@
     celes-release-tryjob
     chell-release-tryjob
     cherry-release-tryjob
+    cherry64-release-tryjob
     coral-kernelnext-release-tryjob
     coral-release-tryjob
+    corsola-release-tryjob
     cyan-release-tryjob
     dedede-release-tryjob
+    draco-release-tryjob
     drallion-release-tryjob
     edgar-release-tryjob
     elm-arc64-release-tryjob
@@ -1325,16 +1306,15 @@
     endeavour-release-tryjob
     eve-arc-r-release-tryjob
     eve-arm64-release-tryjob
-    eve-kernelnext-release-tryjob
     eve-kvm-release-tryjob
     eve-release-tryjob
     eve-userdebug-release-tryjob
     excelsior-release-tryjob
     fizz-cfm-release-tryjob
+    fizz-kernelnext-release-tryjob
     fizz-labstation-release-tryjob
     fizz-moblab-release-tryjob
     fizz-release-tryjob
-    gale-release-tryjob
     goroh-release-tryjob
     grunt-arc-r-release-tryjob
     grunt-kernelnext-release-tryjob
@@ -1349,12 +1329,12 @@
     hatch-arc-r-release-tryjob
     hatch-arc-r-userdebug-release-tryjob
     hatch-arc-s-release-tryjob
+    hatch-arc-t-release-tryjob
     hatch-blueznext-release-tryjob
     hatch-borealis-release-tryjob
     hatch-connectivitynext-release-tryjob
     hatch-diskswap-release-tryjob
     hatch-kernelnext-release-tryjob
-    hatch-manatee-release-tryjob
     hatch-release-tryjob
     herobrine-release-tryjob
     jacuzzi-kernelnext-release-tryjob
@@ -1373,7 +1353,6 @@
     lars-kernelnext-release-tryjob
     lars-release-tryjob
     majolica-release-tryjob
-    mistral-release-tryjob
     mushu-release-tryjob
     nami-kernelnext-release-tryjob
     nami-release-tryjob
@@ -1404,15 +1383,21 @@
     sand-release-tryjob
     sarien-kernelnext-release-tryjob
     sarien-release-tryjob
+    scarlet-kernelnext-release-tryjob
     scarlet-release-tryjob
     senor-release-tryjob
     sentry-release-tryjob
     setzer-release-tryjob
     shadowkeep-release-tryjob
+    skolas-release-tryjob
+    skyrim-chausie-release-tryjob
+    skyrim-kernelnext-release-tryjob
+    skyrim-release-tryjob
     snappy-kernelnext-release-tryjob
     snappy-release-tryjob
     soraka-libcamera-release-tryjob
     soraka-release-tryjob
+    strongbad-kernelnext-release-tryjob
     strongbad-release-tryjob
     tael-release-tryjob
     tatl-release-tryjob
@@ -1424,14 +1409,10 @@
     trogdor-zephyr-release-tryjob
     trogdor64-release-tryjob
     ultima-release-tryjob
-    veyron_fievel-release-tryjob
-    veyron_rialto-release-tryjob
-    veyron_tiger-release-tryjob
     volteer-borealis-release-tryjob
     volteer-kernelnext-release-tryjob
     volteer-manatee-release-tryjob
     volteer-release-tryjob
-    volteer-zephyr-release-tryjob
     wizpig-release-tryjob
     zork-arc-r-release-tryjob
     zork-borealis-release-tryjob
@@ -1440,26 +1421,8 @@
     zork-kernelnext-release-tryjob
     zork-minios-release-tryjob
     zork-release-tryjob
-  master-vmrvc-android-pfq-tryjob
-    eve-arc-r-vmrvc-android-pfq-tryjob
-    grunt-arc-r-vmrvc-android-pfq-tryjob
-    hatch-vmrvc-android-pfq-tryjob
-    kukui-arc-r-vmrvc-android-pfq-tryjob
-    rammus-arc-r-vmrvc-android-pfq-tryjob
-    zork-arc-r-vmrvc-android-pfq-tryjob
-  master-vmsc-android-pfq-tryjob
-    betty-arc-s-vmsc-android-pfq-tryjob
-    hatch-arc-s-vmsc-android-pfq-tryjob
-  master-vmt-android-pfq-tryjob
-    betty-arc-t-vmt-android-pfq-tryjob
   mistral-factory-mistral-12361.B-factorybranch-tryjob
-  mistral-full-tryjob
-  mistral-llvm-next-toolchain-tryjob
-  mistral-llvm-toolchain-tryjob
   mistral-master-factorybranch-tryjob
-  mistral-payloads-tryjob
-  mistral-release-tryjob
-  mistral-unittest-stress
   moblab-generic-vm-full-tryjob
   moblab-generic-vm-llvm-next-toolchain-tryjob
   moblab-generic-vm-llvm-toolchain-tryjob
@@ -1555,8 +1518,6 @@
   octopus-release-tryjob
   octopus-unittest-stress
   orco-factory-rambi-6420.B-factorybranch-tryjob
-  orderfile-generate-toolchain-tryjob
-  orderfile-verify-toolchain-tryjob
   palkia-full-tryjob
   palkia-llvm-next-toolchain-tryjob
   palkia-llvm-toolchain-tryjob
@@ -1614,14 +1575,12 @@
   rammus-arc-r-userdebug-payloads-tryjob
   rammus-arc-r-userdebug-release-tryjob
   rammus-arc-r-userdebug-unittest-stress
-  rammus-arc-r-vmrvc-android-pfq-tryjob
   rammus-factory-rammus-11289.B-factorybranch-tryjob
   rammus-full-tryjob
   rammus-llvm-next-toolchain-tryjob
   rammus-llvm-toolchain-tryjob
   rammus-master-factorybranch-tryjob
   rammus-payloads-tryjob
-  rammus-pi-android-pfq-tryjob
   rammus-release-tryjob
   rammus-unittest-stress
   reef-factory-reef-8811.B-factorybranch-tryjob
@@ -1638,7 +1597,6 @@
   reks-payloads-tryjob
   reks-release-tryjob
   reks-unittest-stress
-  release-afdo-profile-generate-tryjob
   relm-factory-strago-7458.B-factorybranch-tryjob
   relm-full-tryjob
   relm-llvm-next-toolchain-tryjob
@@ -1688,6 +1646,12 @@
   sarien-unittest-stress
   scarlet-factory-scarlet-10211.B-factorybranch-tryjob
   scarlet-full-tryjob
+  scarlet-kernelnext-full-tryjob
+  scarlet-kernelnext-llvm-next-toolchain-tryjob
+  scarlet-kernelnext-llvm-toolchain-tryjob
+  scarlet-kernelnext-payloads-tryjob
+  scarlet-kernelnext-release-tryjob
+  scarlet-kernelnext-unittest-stress
   scarlet-llvm-next-toolchain-tryjob
   scarlet-llvm-toolchain-tryjob
   scarlet-payloads-tryjob
@@ -1719,6 +1683,30 @@
   shadowkeep-payloads-tryjob
   shadowkeep-release-tryjob
   shadowkeep-unittest-stress
+  skolas-full-tryjob
+  skolas-llvm-next-toolchain-tryjob
+  skolas-llvm-toolchain-tryjob
+  skolas-payloads-tryjob
+  skolas-release-tryjob
+  skolas-unittest-stress
+  skyrim-chausie-full-tryjob
+  skyrim-chausie-llvm-next-toolchain-tryjob
+  skyrim-chausie-llvm-toolchain-tryjob
+  skyrim-chausie-payloads-tryjob
+  skyrim-chausie-release-tryjob
+  skyrim-chausie-unittest-stress
+  skyrim-full-tryjob
+  skyrim-kernelnext-full-tryjob
+  skyrim-kernelnext-llvm-next-toolchain-tryjob
+  skyrim-kernelnext-llvm-toolchain-tryjob
+  skyrim-kernelnext-payloads-tryjob
+  skyrim-kernelnext-release-tryjob
+  skyrim-kernelnext-unittest-stress
+  skyrim-llvm-next-toolchain-tryjob
+  skyrim-llvm-toolchain-tryjob
+  skyrim-payloads-tryjob
+  skyrim-release-tryjob
+  skyrim-unittest-stress
   sludge-full-tryjob
   sludge-llvm-next-toolchain-tryjob
   sludge-llvm-toolchain-tryjob
@@ -1753,6 +1741,12 @@
   strongbad-factory-strongbad-13963.B-factorybranch-tryjob
   strongbad-factory-trogdor-13443.B-factorybranch-tryjob
   strongbad-full-tryjob
+  strongbad-kernelnext-full-tryjob
+  strongbad-kernelnext-llvm-next-toolchain-tryjob
+  strongbad-kernelnext-llvm-toolchain-tryjob
+  strongbad-kernelnext-payloads-tryjob
+  strongbad-kernelnext-release-tryjob
+  strongbad-kernelnext-unittest-stress
   strongbad-llvm-next-toolchain-tryjob
   strongbad-llvm-toolchain-tryjob
   strongbad-payloads-tryjob
@@ -1827,12 +1821,6 @@
   ultima-release-tryjob
   ultima-unittest-stress
   veyron_fievel-factory-veyron-7505.B-factorybranch-tryjob
-  veyron_fievel-full-tryjob
-  veyron_fievel-llvm-next-toolchain-tryjob
-  veyron_fievel-llvm-toolchain-tryjob
-  veyron_fievel-payloads-tryjob
-  veyron_fievel-release-tryjob
-  veyron_fievel-unittest-stress
   veyron_mighty-full-tryjob
   veyron_mighty-llvm-next-toolchain-tryjob
   veyron_mighty-llvm-toolchain-tryjob
@@ -1845,13 +1833,6 @@
   veyron_minnie-payloads-tryjob
   veyron_minnie-release-tryjob
   veyron_minnie-unittest-stress
-  veyron_rialto-factory-veyron-7505.B-factorybranch-tryjob
-  veyron_rialto-full-tryjob
-  veyron_rialto-llvm-next-toolchain-tryjob
-  veyron_rialto-llvm-toolchain-tryjob
-  veyron_rialto-payloads-tryjob
-  veyron_rialto-release-tryjob
-  veyron_rialto-unittest-stress
   veyron_speedy-full-tryjob
   veyron_speedy-llvm-next-toolchain-tryjob
   veyron_speedy-llvm-toolchain-tryjob
@@ -1859,12 +1840,6 @@
   veyron_speedy-release-tryjob
   veyron_speedy-unittest-stress
   veyron_tiger-factory-veyron-7505.B-factorybranch-tryjob
-  veyron_tiger-full-tryjob
-  veyron_tiger-llvm-next-toolchain-tryjob
-  veyron_tiger-llvm-toolchain-tryjob
-  veyron_tiger-payloads-tryjob
-  veyron_tiger-release-tryjob
-  veyron_tiger-unittest-stress
   viking-full-tryjob
   viking-llvm-next-toolchain-tryjob
   viking-llvm-toolchain-tryjob
@@ -1902,12 +1877,6 @@
   volteer-payloads-tryjob
   volteer-release-tryjob
   volteer-unittest-stress
-  volteer-zephyr-full-tryjob
-  volteer-zephyr-llvm-next-toolchain-tryjob
-  volteer-zephyr-llvm-toolchain-tryjob
-  volteer-zephyr-payloads-tryjob
-  volteer-zephyr-release-tryjob
-  volteer-zephyr-unittest-stress
   whirlwind-full-tryjob
   whirlwind-llvm-next-toolchain-tryjob
   whirlwind-llvm-toolchain-tryjob
@@ -1930,7 +1899,6 @@
   wristpin-release-tryjob
   wristpin-unittest-stress
   x32-generic-full-tryjob
-  x32-generic-incremental-tryjob
   x32-generic-llvm-next-toolchain-tryjob
   x32-generic-llvm-toolchain-tryjob
   x32-generic-unittest-stress
@@ -1940,7 +1908,6 @@
   zork-arc-r-payloads-tryjob
   zork-arc-r-release-tryjob
   zork-arc-r-unittest-stress
-  zork-arc-r-vmrvc-android-pfq-tryjob
   zork-borealis-full-tryjob
   zork-borealis-llvm-next-toolchain-tryjob
   zork-borealis-llvm-toolchain-tryjob
diff --git a/contrib/depgraph_visualization/README.md b/contrib/depgraph_visualization/README.md
index 1b8fc7b..f94a04c 100644
--- a/contrib/depgraph_visualization/README.md
+++ b/contrib/depgraph_visualization/README.md
@@ -7,7 +7,7 @@
 
 ```bash
 cros_sdk --enter
-cd ~/trunk/chromite/contrib/depgraph_visualization
+cd ~/chromiumos/chromite/contrib/depgraph_visualization
 ./install.sh
 source my_visualizations/bin/activate
 cd my_visualizations
diff --git a/bin/cros_check_patches b/contrib/generate_cs_path
similarity index 100%
copy from bin/cros_check_patches
copy to contrib/generate_cs_path
diff --git a/contrib/generate_cs_path.py b/contrib/generate_cs_path.py
new file mode 100644
index 0000000..605e102
--- /dev/null
+++ b/contrib/generate_cs_path.py
@@ -0,0 +1,154 @@
+# Copyright 2022 The Chromium OS 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 with an IDE to copy a link to the current file/line to your clipboard.
+
+Public and private repos are supported. The internal/public arguments are only
+used if the repo is public, private repos always link to the internal code
+search.
+
+By default always generates a link to the public code search, but can also
+generate links to the internal code search.
+
+Currently only works locally and if using X11.
+
+To allow use over SSH, enable X11 forwarding.
+Client side: -X, or add "X11Forwarding yes" to your ~/.ssh/config.
+Server side: "X11Forwarding yes" must be in /etc/ssh/sshd_config.
+
+IDE integration instructions. Please add your IDE if it's not listed, or update
+the instructions if they're vague or out of date!
+
+For Intellij:
+Create a new External Tool (Settings > Tools > External Tools).
+Tool Settings:
+  Program: ~/chromiumos/chromite/contrib/generate_cs_path
+  Arguments: $FilePath$ -l $LineNumber$
+
+For VSCode:
+Create a custom task (code.visualstudio.com/docs/editor/tasks#_custom-tasks)
+with the command:
+  ~/chromiumos/chromite/contrib/generate_cs_path ${file} -l ${lineNumber}
+"""
+
+import os
+from pathlib import Path
+import sys
+
+from chromite.lib import commandline
+from chromite.lib import constants
+from chromite.lib import cros_build_lib
+from chromite.lib import git
+
+# HEAD is the ref for the codesearch repo, not the project itself.
+_PUBLIC_CS_BASE = (
+    'https://source.chromium.org/chromiumos/chromiumos/codesearch/+/HEAD:')
+_INTERNAL_CS_BASE = 'http://cs/chromeos_public/'
+_INTERNAL_CS_PRIVATE_BASE = 'http://cs/chromeos_internal/'
+
+
+def GetParser():
+  """Build the argument parser."""
+  parser = commandline.ArgumentParser(description=__doc__)
+
+  # Public/internal code search selection arguments.
+  type_group = parser.add_mutually_exclusive_group()
+  type_group.add_argument(
+      '-p',
+      '--public',
+      dest='public_link',
+      action='store_true',
+      default=True,
+      help='Generate a link to the public code search.')
+  type_group.add_argument(
+      '-i',
+      '--internal',
+      dest='public_link',
+      action='store_false',
+      help='Generate a link to the internal code search.')
+  type_group.add_argument(
+      '-g',
+      '--gitiles',
+      action='store_true',
+      default=False,
+      help='Generate a gitiles link rather than a code search link.'
+  )
+
+  parser.add_argument('-l', '--line', type=int, help='Line number.')
+
+  action_group = parser.add_mutually_exclusive_group()
+  action_group.add_argument(
+      '-o',
+      '--open',
+      action='store_true',
+      default=False,
+      help='Open the link in a browser rather than copying it to the clipboard.'
+  )
+  action_group.add_argument(
+      '-s',
+      '--show',
+      action='store_true',
+      default=False,
+      help='Output the link to stdout rather than copying it to the clipboard.'
+  )
+
+  parser.add_argument('path', type='path', help='Path to a file.')
+
+  return parser
+
+
+def _ParseArguments(argv):
+  """Parse and validate arguments."""
+  parser = GetParser()
+  opts = parser.parse_args(argv)
+
+  opts.path = Path(opts.path).relative_to(constants.SOURCE_ROOT)
+
+  opts.Freeze()
+  return opts
+
+
+def main(argv):
+  opts = _ParseArguments(argv)
+
+  checkout = git.ManifestCheckout.Cached(opts.path)
+
+  # Find the project.
+  checkout_path = None
+  attrs = {}
+  for checkout_path, attrs in checkout.checkouts_by_path.items():
+    try:
+      relative_path = opts.path.relative_to(checkout_path)
+      break
+    except ValueError:
+      continue
+  else:
+    cros_build_lib.Die('No project found for %s.', opts.path)
+
+  if opts.gitiles:
+    final_link = (f"{attrs.get('push_url')}/+/{attrs.get('revision')}/"
+                  f'{relative_path}#{opts.line}')
+  else:
+    line = f';l={opts.line}' if opts.line else ''
+
+    if attrs.get('remote_alias') == 'cros-internal':
+      # Private repos not on public CS, so force internal private.
+      base = _INTERNAL_CS_PRIVATE_BASE
+    elif opts.public_link:
+      base = _PUBLIC_CS_BASE
+    else:
+      base = _INTERNAL_CS_BASE
+
+    final_link = f'{base}{checkout_path}/{relative_path}{line}'
+
+  is_mac_os = sys.platform.startswith('darwin')
+
+  if opts.open:
+    cmd = ['open' if is_mac_os else 'xdg-open', final_link]
+    os.execvp(cmd[0], cmd)
+  elif opts.show:
+    print(final_link)
+  else:
+    cmd = ['pbcopy'] if is_mac_os else ['xsel', '--clipboard', '--input']
+    cros_build_lib.run(cmd, input=final_link)
diff --git a/contrib/get_hash_for_release b/contrib/get_hash_for_release
deleted file mode 100755
index 9b3497c..0000000
--- a/contrib/get_hash_for_release
+++ /dev/null
@@ -1,173 +0,0 @@
-#!/bin/bash
-# Copyright 2014 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# The "get_hash_for_release" command can be used in one of two forms:
-#  - It can be used to return the hash associated with the project in
-#    the current directory:
-#
-#      ~/chromiumos/chromite$ get_hash_for_release 6822.0.0
-#      0b325183cf2eee7f93d7d631a8639c089f4a2d4f
-#      # This is the hash of the "chromite" package for release 6822.0.0
-#
-#  - It can indicate what is the earliest release where a given hash
-#    appeared:
-#
-#     ~/chromiumos/chromite$ get_hash_for_release R41 \
-#         8eba257003357ca945528fb93dadd2c4d16b7d11
-#     Oldest release with 8eba257003357ca945528fb93dadd2c4d16b7d11 is 6674.0.0
-
-
-fetch_manifests() {
-  temp_dir=/tmp/chrome_manifest_temp
-  if [[ ! -d "${temp_dir}" ]] ; then
-    mkdir -p "${temp_dir}"
-    local git_server="https://chrome-internal.googlesource.com"
-    git clone -q --depth 1 --single-branch \
-        "${git_server}/chromeos/manifest-versions" "${temp_dir}"
-  else
-    (cd "${temp_dir}" && git pull -q)
-  fi
-}
-
-cleanup_manifests() {
-  if [[ -d "${temp_dir}" ]] ; then
-    rm -rf "${temp_dir}"
-  fi
-}
-
-is_child_release() {
-  # Release numbers are stated in a set of dotted integers.
-  # 2.0.0.0 is a child of 1.0.0.0 (later release)
-  # 2.1.0.0 is a child of 2.0.0.0 (new branch)
-  # 3.0.0.0 is a child of 2.0.0.0 but not 2.1.0.0 since 2.1 branched from 2.0.
-  # 3.0.1.0 isn't really valid (branches are left aligned) but we ignore this.
-
-  local child
-  local parent
-  IFS='.' read -a child <<< "$1"
-  IFS='.' read -a parent <<< "$2"
-  if [[ ${#child[@]} -ne ${#parent[@]} ]] ; then
-    return 1
-  fi
-
-  local must_be_root
-  for idx in $(seq 0 $((${#child[@]} - 1))); do
-    local parent_num="${parent[idx]}"
-    [[ -n "${must_be_root}" && "$parent_num" != "0" ]] && return 1
-    local child_num="${child[idx]}"
-    [[ "${parent_num}" > "${child_num}" ]] && return 1
-    [[ "${parent_num}" < "${child_num}" ]] && must_be_root=1
-  done
-  return 0
-}
-
-get_project_info() {
-  repo info . 2>/dev/null | egrep '^(Project|Current revision):' | cut -f2 -d:
-}
-
-get_revision() {
-  local release="$1"
-  local revision="$2"
-  grep "${project}.*upstream=.*${branch}" \
-      ${temp_dir}/buildspecs/$release/${revision}.xml |
-      sed -e 's/ *<project.*revision="\([^"]*\)".*/\1/' \
-          -e 's/^.*\/\([0-9.]*\)\.xml:/\1 : /'
-}
-
-get_hash_for_release() {
-  get_revision '*' "${revision}"
-}
-
-get_release_for_hash() {
-  local release="${revision:1}"
-  local -a all_revs=($(ls "${temp_dir}/buildspecs/${release}" |
-                       sort -Vr | sed -e 's/\.xml$//'))
-  latest_rev=$(basename $(cd "${temp_dir}/buildspecs/${release}" &&
-                          git log -n1 --name-only --oneline --grep release . |
-                          grep -v ' ' | sort -V | tail -1 |
-                          sed -e 's/\.xml$//'))
-  revs=()
-  for rev in "${all_revs[@]}"; do
-    is_child_release "${latest_rev}" "${rev}" && revs+=("${rev}")
-  done
-  last_released_hash=$(get_revision "${release}" "${latest_rev}" |
-                       awk '{print $1}')
-  if [[ -z "${last_released_hash}" ]] ; then
-    echo "Huh?  Can't find hash for ${latest_rev}"
-    return
-  fi
-  local -a hashes
-  found=''
-  for search_size in 10 100 1000 10000; do
-    hashes=($(git log --pretty=format:%H -n "${search_size}" \
-              "${last_released_hash}"))
-    if echo "${hashes[*]}" | grep -q $hash; then
-      found=1
-      break
-    fi
-  done
-  if [[ -z "${found}" ]] ; then
-    echo "Perhaps ${hash} was never in release ${release}?"
-    return
-  fi
-  # Pop all hashes after the one we care about.
-  while [[ "${hashes[-1]}" != "${hash}" ]] ; do
-    unset hashes[${#hashes[@]}-1]
-  done
-  oldest_release="${latest_rev}"
-  idx=1
-  while [[ $idx -lt ${#revs[@]} ]]; do
-    rev="${revs[idx]}"
-    hash_for_rev=$(get_revision "${release}" "${rev}" |
-                   awk '{print $1}')
-    if ! echo "${hashes[*]}" | grep -q $hash_for_rev; then
-      break
-    fi
-    oldest_release="${rev}"
-    idx=$(( idx + 1 ))
-  done
-  echo "Oldest release with ${hash} is ${oldest_release}"
-}
-
-main() {
-  revision="${1}"
-  if [[ -z "${revision}"  ]] ; then
-    echo "Usage: $0 <revision> [hash]"
-    exit 0
-  fi
-
-  if expr "${revision}" : '[MR]' > /dev/null; then
-    hash="${2}"
-    shift
-  fi
-
-  project_info=($(get_project_info))
-
-  if [[ "${#project_info[@]}" < 2 ]] ; then
-    echo "Couldn't get project info (are you in a repo directory?)"
-    exit 0
-  fi
-
-  project="${project_info[0]}"
-  branch="$(echo ${project_info[1]} | cut -d/ -f3)"
-  if [[ "${branch}" == "master" ]] ; then
-    branch=""
-  elif [[ "${branch}" == "chromeos-3.4" ]] ; then
-    # Hack for old releases of chromeos-kernel.
-    branch='\.[4B]"'
-  fi
-
-  fetch_manifests
-
-  if [[ -z "${hash}" ]] ; then
-    get_hash_for_release
-  else
-    get_release_for_hash
-  fi
-
-  #cleanup_manifests
-}
-
-main "$@"
diff --git a/contrib/guestos/deploy_to_termina.py b/contrib/guestos/deploy_to_termina.py
index 90807ae..cf2e067 100644
--- a/contrib/guestos/deploy_to_termina.py
+++ b/contrib/guestos/deploy_to_termina.py
@@ -114,6 +114,9 @@
 
     logging.notice('Transferring files')
     for transfer in transfers:
+      if not transfer.files:
+        # If we don't have any files don't call rsync
+        continue
       logging.info('Deploying the following files to the %s image: %s',
                    transfer.destination_image, ', '.join(transfer.files))
       with tempfile.TemporaryDirectory() as d:
diff --git a/bin/cros_check_patches b/contrib/zephyr_downstream
similarity index 100%
copy from bin/cros_check_patches
copy to contrib/zephyr_downstream
diff --git a/contrib/zephyr_downstream.py b/contrib/zephyr_downstream.py
new file mode 100755
index 0000000..8aad21a
--- /dev/null
+++ b/contrib/zephyr_downstream.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python3
+# Copyright 2022 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""CR and CQ +2 Zephyr commits for downstreaming.
+
+For Zephyr Downstreaming Rotation: go/zephyr-downstreaming-guide
+"""
+
+import logging
+
+from chromite.lib import commandline
+from chromite.lib import config_lib
+from chromite.lib import gerrit
+
+
+def main(args):
+  """Downstream Zephyr CLs."""
+  # TODO(aaronmassey): Add option to rebase CLs.
+  parser = commandline.ArgumentParser(__doc__)
+  parser.add_argument('--dry-run',
+                      action='store_true',
+                      help='Dry run, no updates to Gerrit.')
+  opts = parser.parse_args(args)
+  dry_run = opts.dry_run
+
+  site_params = config_lib.GetSiteParams()
+  cros = gerrit.GetGerritHelper(site_params.EXTERNAL_REMOTE)
+
+  cls_to_downstream = cros.Query(topic='zephyr-downstream', status='open',
+                                 raw=True)
+  cls_to_downstream.sort(key=lambda patch: patch['number'])
+
+  logging.info('Downstreaming the following CLs:\n%s',
+               '\n'.join((patch['number'] for patch in cls_to_downstream)))
+
+  # TODO(aaronmassey): Investigate bulk changes from Gerrit lib API instead.
+  for i, patch in enumerate(cls_to_downstream):
+    change_num = patch['number']
+    logging.info('Downstreaming %s: %d/%d',
+                 change_num,
+                 i + 1,
+                 len(cls_to_downstream))
+
+    cros.SetReviewers(change=change_num, dryrun=dry_run, notify='NONE')
+    cros.SetReview(change=change_num,
+                   dryrun=dry_run,
+                   # Add Verified label because client POST removes it.
+                   labels={'Verified': '1',
+                           'Code-Review': '2',
+                           'Commit-Queue': '2', })
+
+  logging.info('All finished! Remember to monitor the CQ!')
diff --git a/cros/test/image_test.py b/cros/test/image_test.py
index bdfaf6e..1c94ed8 100644
--- a/cros/test/image_test.py
+++ b/cros/test/image_test.py
@@ -27,8 +27,9 @@
 from chromite.third_party import lddtree
 from chromite.third_party.pyelftools.elftools.common import exceptions
 from chromite.third_party.pyelftools.elftools.elf import elffile
-import magic  # pylint: disable=import-error
+import magic  # pylint: disable=import-error,wrong-import-order
 
+# pylint: disable=ungrouped-imports
 from chromite.cros.test import usergroup_baseline
 from chromite.lib import cros_build_lib
 from chromite.lib import filetype
@@ -695,10 +696,6 @@
       '/etc/machine-id': {'/var/lib/dbus/machine-id'},
       '/etc/mtab': {'/proc/mounts'},
 
-      # The kip board has a broken/dangling symlink.  Allow it until we can
-      # rewrite the code.  Or kip goes EOL.
-      '/lib/firmware/elan_i2c.bin': {'/opt/google/touch/firmware/*'},
-
       # Some boards don't set this up properly.  It's not a big deal.
       '/usr/libexec/editor': {'/usr/bin/*'},
 
diff --git a/cros/test/usergroup_baseline.py b/cros/test/usergroup_baseline.py
index 68b0e8b..e0f2816 100644
--- a/cros/test/usergroup_baseline.py
+++ b/cros/test/usergroup_baseline.py
@@ -121,10 +121,9 @@
                                             'bootlockboxd', 'chaps',
                                             'oobe_config_restore',
                                             'oobe_config_save',
-                                            'tpm_manager', 'trunks'}),
+                                            'tpm_manager', 'trunks', 'u2f'}),
     GroupEntry(group='pkcs11', gid=208, users={'root', 'vpn', 'chronos',
                                                'chaps', 'wpa', 'attestation'}),
-    GroupEntry(group='ipsec', gid=212),
     GroupEntry(group='wpa', gid=219, users={'root'}),
     GroupEntry(group='input', gid=222, users={'cras', 'power', 'chronos'}),
     GroupEntry(group='brltty', gid=240, users={'chronos'}),
@@ -173,12 +172,13 @@
                                                        'power',
                                                        'typecd_ec'}),
     GroupEntry(group='virtaccess', gid=418, users={'crosvm', 'wilco_dtc'}),
-    GroupEntry(group='crash-access', gid=419, users={'crash'}),
+    GroupEntry(group='crash-access', gid=419, users={'crash', 'secanomaly'}),
     GroupEntry(group='crash-user-access', gid=420,
                users={'crash', 'chronos', 'vm_cicerone'}),
     GroupEntry(group='pstore-access', gid=422, users={'debugd',
                                                       'oobe_config_restore'}),
     GroupEntry(group='bluetooth-audio', gid=423, users={'bluetooth', 'cras'}),
+    GroupEntry(group='ppp', gid=424, users={'shill', 'vpn'}),
 
     GroupEntry(group='cras', gid=600, users={'chronos', 'crosvm', 'power',
                                              'rtanalytics', 'sound_card_init'}),
@@ -195,9 +195,8 @@
 
     GroupEntry(group='chronos', gid=1000),
     GroupEntry(group='chronos-access', gid=1001,
-               users={'root', 'vpn', 'chronos',
-                      'cros-disks', 'imageloaderd', 'crash', 'dlp',
-                      'image-burner'}),
+               users={'vpn', 'chronos', 'cros-disks', 'imageloaderd', 'crash',
+                      'dlp', 'image-burner', 'spaced'}),
 
     GroupEntry(group='user-containers', gid=10000, users={'user-containers'}),
 
@@ -206,7 +205,7 @@
                                                  'cups', 'saned'}),
     GroupEntry(group='cfm-peripherals', gid=20103,
                users={'cfm-monitor', 'cfm-firmware-updaters'}),
-    GroupEntry(group='shill', gid=20104, users={'shill', 'vpn'}),
+    GroupEntry(group='shill', gid=20104, users={'shill'}),
     GroupEntry(group='pluginvm', gid=20128, users={'crosvm', 'pluginvm'}),
     GroupEntry(group='kerberosd', gid=20131, users={'kerberosd',
                                                     'kerberosd-exec'}),
diff --git a/docs/cli-guidelines.md b/docs/cli-guidelines.md
new file mode 100644
index 0000000..ccab574
--- /dev/null
+++ b/docs/cli-guidelines.md
@@ -0,0 +1,245 @@
+# CLI Guidelines
+
+Define standard options to create a consistent CLI experience across tools.
+When developers get used to certain option behavior, having them available
+across all tools makes things much easier & smoother.
+Conversely, when the same option name is used but with wildly different
+meanings, this can be very surprising for developers, and possibly lead them
+to do something destructive they didn't intend.
+
+[TOC]
+
+## Required Option Conventions
+
+Tools should adhere to these conventions whenever possible, and any deviation
+should be strongly reconsidered.
+
+| Short | Long          | Description |
+|:-----:|---------------|-------------|
+|       | [--debug]     | Show debugging information. |
+| [-f]  | [--force]     | Force an operation. |
+| [-h]  | [--help]      | Show tool help/usage output. |
+| [-j]  | [--jobs]      | Control parallelization. |
+| [-n]  | [--dry-run]   | Show what would be done. |
+| [-q]  | [--quiet]     | Quiet(er) output. |
+| [-v]  | [--verbose]   | Verbose(r) output. |
+|       | [--version]   | Show tool version information. |
+| [-y]  | [--yes]       | Skip prompts. |
+
+### --debug {#debug}
+
+Show internal debugging information that the user would find helpful.
+This may be very verbose.
+
+[--debug] may be specified multiple times to make the output even debuggier.
+
+The short option [-d] may be used depending on the tool, but usually enabling
+extra debugging is not a common operation.
+
+[-d]: #debug
+[--debug]: #debug
+
+### --force {#force}
+
+The user wants to bypass any safety checks.
+The help text should provide clear guidance on how this will affect behavior
+since it can potentially be very dangerous and lead to data loss.
+
+For example, when imaging a device, do not prompt the user whether they really
+meant to erase the non-removable `/dev/sda` hard drive.
+Or if there are mismatches in hashes or other integrity checks, attempt to do
+the operation anyways (installing files, etc...).
+
+Do not confuse this with the [--yes] option for agreeing to common prompts.
+
+The short option [-f] may be used or omitted depending on how dangerous the
+option actually is in practice.
+If the tool might delete the user's desktop or source, probably safer to make
+them type out the full [--force].
+If the tool would only delete some temporary files or something that could be
+recreated (even if it requires a bit of effort), then [-f] is OK.
+
+[-f]: #force
+[--force]: #force
+
+### --help {#help}
+
+Show the tool usage, examples, and other helpful information.
+Since the user has explicitly requested the help output, this does not need to
+be terse.
+Normal output should only go to stdout, and the tool should exit 0.
+
+When processing unknown or invalid options, it's OK to show a short summary of
+the specific option, or of valid options, but it should not be the full detailed
+output like [--help].
+The user should be able to focus on what they got wrong, not wade throw pages of
+output to try and track down the one error line.
+This output should only go to stderr, and the tool should exit non-zero (either
+`1` or `64`).
+
+Use of the short [-h] option is recommended out of wide convention.
+Avoid reusing this for something else like `--human`, and definitely never use
+it for something destructive or unrecoverable.
+
+[-h]: #help
+[--help]: #help
+
+### --jobs {#jobs}
+
+Limit how much parallelism should be used.
+This typically translates to how many threads or CPUs to utilize.
+
+The special value `0` should be used to indicate "use all available CPU cores".
+
+The default does not have to always be `1` thus forcing users to manually pick
+a value, nor does it have to always be `0`.
+Try to balance how expensive a particular job is (network, servers, I/O, RAM,
+etc...) with a reasonable default.
+For example, when talking to a network service, high values like 72 will
+probably cause many connections to be rejected so it won't be overwhelmed, so
+find a default that balances real world improvements (compared to `-j1`) with
+the server costs.
+
+The default should rarely be hardcoded to a value above 1 -- run it through a
+max function with how many cores are available.
+For example, the default could be `max(4, os.cpu_count())`.
+
+To determine how many CPU cores are available:
+* Python: `os.cpu_count()`
+* Shell: `getconf _NPROCESSORS_CONF 2>/dev/null || echo 1`
+
+Use of the short [-j] option is recommended out of wide convention.
+
+[-j]: #jobs
+[--jobs]: #jobs
+
+### --dry-run {#dryrun}
+
+Show what would be done, but don't actually "do" anything.
+Users should be able to add this option anywhere and expect that the tool will
+not make any changes anywhere.
+Basically this should always be a harmless idempotent operation.
+
+Use of [--dry-run] is, by itself, not an error, thus it should normally exit 0.
+This allows the user to quickly detect problems before trying to make changes.
+For example, if invalid options were specified, the tool can show fatal errors.
+Or if inputs don't exist, or are corrupt, they may be diagnosed.
+
+The tool may talk to network services, or otherwise make expensive computations,
+as long as it doesn't make any changes, and may be rerun many times.
+
+The tool should display what it would have done were [--dry-run] not specified.
+This will often take the form like `Would have run command: git push ...`.
+
+Bypassing reasonable prompts is permitted as long as no changes are made.
+In other words, this may behave like [--yes] or [--force] in some situations.
+Use your best judgment as to what constitutes the best user experience.
+
+Use of the short [-n] option is recommended out of wide convention, and because
+use of dry-run first is a common user flow.
+
+The [--dryrun] option should be accepted as an alias to [--dry-run], but should
+be omitted from documentation (i.e. [--help] output).
+This helps users who typo things, and because some tools have adopted one that
+convention instead of [--dry-run] (although the latter is still more common).
+
+[-n]: #dryrun
+[--dry-run]: #dryrun
+[--dryrun]: #dryrun
+
+### --quiet {#quiet}
+
+Make the output less verbose.
+General information should be omitted, and only display warnings or errors.
+
+[--quiet] may be specified multiple times to make the output even quieter.
+Some recommended settings:
+* *default*: Show important events, warnings, and worse.
+* `-q`: Only show warnings and worse.
+* `-qq`: Only show (fatal) errors and worse.
+* `-qqq`: Don't show any output -- rely on exit status to indicate pass/fail.
+
+Use of the short [-q] option is recommended out of wide convention.
+
+If desired, [--silent] may be used as an alias to `-qqq` behavior; i.e. do not
+emit any output, only exit 0/non-zero.
+
+[-q]: #quiet
+[--quiet]: #quiet
+[--silent]: #quiet
+
+### --verbose
+
+Make the output more verbose.
+This may include some helpful info or progress steps.
+Important information for the user should not be hidden behind [--verbose];
+i.e. users should not be expected to use [--verbose] all the time.
+
+[--verbose] may be specified multiple times to make the output even verboser.
+
+Debugging information should not be included here -- use [--debug] instead.
+Use your best judgement as to what is verbose output and what is debug output.
+
+Use of the short [-v] option is recommended out of wide convention, and because
+it can be common to type `-vvv` to quickly get more verbose output when trying
+to track down problems.
+
+[-v]: #verbose
+[--verbose]: #verbose
+
+### --version {#version}
+
+Show version information for the current tool.
+Normal output should only go to stdout, and the tool should exit 0.
+
+The default output should be short & to the point, and cheap to produce.
+This may include terse authorship information if desired.
+
+If combined with [--verbose], related package/tool information may be included.
+
+If combined with [--quiet], the output should be just the version number.
+
+For example, common output might look like:
+```
+$ tool --version
+CrOS tool v1.2.3
+Written by some decent engineers.
+
+$ tool --version --quiet
+1.2.3
+
+$ tool --version --verbose
+CrOS tool v1.2.3
+Current git repo is at add119cea9ebfd7ba89f7606ed04cac7cacaa43d.
+
+Some important library information:
+  foo lib v2
+  another lib v3.4
+
+Written by some decent engineers.
+```
+
+No short option should be provided for [--version].
+It's not a common operation, so allocating one of the limited short options
+is a waste.
+
+[--version]: #version
+
+### --yes {#yes}
+
+The user wants to "agree" to any standard prompts shown by the tool.
+This should not be used by itself to bypass safety checks -- see [--force]
+instead, with which this can be combined.
+
+The prompts that would have been shown should still be emitted so it's clear
+what the user has agreed to, and include fake input.  For example:
+```
+$ do-something --yes
+Do you want to do something? (Y/n) <yes>
+```
+
+Use of the short [-y] option is recommended out of wide convention, and because
+skipping the same set of prompts is a common flow to avoid annoying users.
+
+[-y]: #yes
+[--yes]: #yes
diff --git a/ide_tooling/.presubmitignore b/ide_tooling/.presubmitignore
new file mode 100644
index 0000000..8bba3f8
--- /dev/null
+++ b/ide_tooling/.presubmitignore
@@ -0,0 +1,2 @@
+cros-ide/tsconfig.json
+cros-ide/.vscode/*.json
diff --git a/ide_tooling/OWNERS b/ide_tooling/OWNERS
new file mode 100644
index 0000000..3f519f2
--- /dev/null
+++ b/ide_tooling/OWNERS
@@ -0,0 +1,5 @@
+lokeric@chromium.org
+nya@chromium.org
+oka@chromium.org
+ttylenda@chromium.org
+yoshiki@chromium.org
diff --git a/ide_tooling/README.md b/ide_tooling/README.md
new file mode 100644
index 0000000..ef9c0a4
--- /dev/null
+++ b/ide_tooling/README.md
@@ -0,0 +1,16 @@
+# IDE Tooling
+
+IDE tools for Chrome OS developers.
+
+- [Quickstart]
+
+[Quickstart]: ./docs/quickstart.md
+
+# Main Components
+-  cros-sdk proxy
+
+Details TBD
+
+-  vscode plugin
+
+Details TBD
diff --git a/ide_tooling/cros-ide/.eslintrc.js b/ide_tooling/cros-ide/.eslintrc.js
new file mode 100644
index 0000000..29acf58
--- /dev/null
+++ b/ide_tooling/cros-ide/.eslintrc.js
@@ -0,0 +1,31 @@
+// Copyright 2022 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module.exports = {
+  'env': {
+    'browser': true,
+    'es2021': true,
+  },
+  'extends': [
+    'google',
+  ],
+  'parser': '@typescript-eslint/parser',
+  'parserOptions': {
+    'ecmaVersion': 'latest',
+    'sourceType': 'module',
+  },
+  'plugins': [
+    '@typescript-eslint',
+  ],
+  'rules': {
+    // These rules should be enabled but are temporary disabled until the
+    // violations are removed from the code.
+    'require-jsdoc': 0,
+    'arrow-parens': 0,
+    'max-len': ['error', {code: 100}],
+    'no-throw-literal': 0,
+    'no-invalid-this': 0,
+    'valid-jsdoc': 0, // has been deprecated in ESLint v5.10.0.
+  },
+};
diff --git a/ide_tooling/cros-ide/.gitignore b/ide_tooling/cros-ide/.gitignore
new file mode 100644
index 0000000..2ed7813
--- /dev/null
+++ b/ide_tooling/cros-ide/.gitignore
@@ -0,0 +1,6 @@
+node_modules/*
+!node_modules/README.md
+*.js.map
+dist/*
+out/*
+.vscode-test/*
diff --git a/ide_tooling/cros-ide/.vscode/README.md b/ide_tooling/cros-ide/.vscode/README.md
new file mode 100644
index 0000000..ee153b2
--- /dev/null
+++ b/ide_tooling/cros-ide/.vscode/README.md
@@ -0,0 +1 @@
+Shared configs for cros-ide developers.
diff --git a/ide_tooling/cros-ide/.vscode/extensions.json b/ide_tooling/cros-ide/.vscode/extensions.json
new file mode 100644
index 0000000..57dbdae
--- /dev/null
+++ b/ide_tooling/cros-ide/.vscode/extensions.json
@@ -0,0 +1,5 @@
+{
+  // See http://go.microsoft.com/fwlink/?LinkId=827846
+  // for the documentation about the extensions.json format
+  "recommendations": ["dbaeumer.vscode-eslint", "amodio.tsl-problem-matcher"]
+}
diff --git a/ide_tooling/cros-ide/.vscode/launch.json b/ide_tooling/cros-ide/.vscode/launch.json
new file mode 100644
index 0000000..7fc26e0
--- /dev/null
+++ b/ide_tooling/cros-ide/.vscode/launch.json
@@ -0,0 +1,49 @@
+// A launch configuration that compiles the extension and then opens it inside a new window
+// Use IntelliSense to learn about possible attributes.
+// Hover to view descriptions of existing attributes.
+// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+{
+  "version": "0.2.0",
+  "configurations": [
+    {
+      "name": "Run Extension",
+      "type": "extensionHost",
+      "request": "launch",
+      "args": [
+        "--disable-extensions",
+        "--extensionDevelopmentPath=${workspaceFolder}"
+      ],
+      "outFiles": [
+        "${workspaceFolder}/dist/**/*.js"
+      ],
+      "preLaunchTask": "${defaultBuildTask}"
+    },
+    {
+      "name": "Run Extension (keep other extensions running)",
+      "type": "extensionHost",
+      "request": "launch",
+      "args": [
+        "--extensionDevelopmentPath=${workspaceFolder}"
+      ],
+      "outFiles": [
+        "${workspaceFolder}/dist/**/*.js"
+      ],
+      "preLaunchTask": "${defaultBuildTask}"
+    },
+    {
+      "name": "Extension Tests",
+      "type": "extensionHost",
+      "request": "launch",
+      "args": [
+        "--disable-extensions",
+        "--extensionDevelopmentPath=${workspaceFolder}",
+        "--extensionTestsPath=${workspaceFolder}/out/test/integration/index"
+      ],
+      "outFiles": [
+        "${workspaceFolder}/out/**/*.js",
+        "${workspaceFolder}/dist/**/*.js"
+      ],
+      "preLaunchTask": "tasks: compile-tests"
+    }
+  ]
+}
diff --git a/ide_tooling/cros-ide/.vscode/settings.json b/ide_tooling/cros-ide/.vscode/settings.json
new file mode 100644
index 0000000..6dff237
--- /dev/null
+++ b/ide_tooling/cros-ide/.vscode/settings.json
@@ -0,0 +1,35 @@
+// Place your settings in this file to overwrite default and user settings.
+{
+  "files.exclude": {
+    "out": false, // set this to true to hide the "out" folder with the compiled JS files
+    "dist": false // set this to true to hide the "dist" folder with the compiled JS files
+  },
+  "search.exclude": {
+    "out": true, // set this to false to include "out" folder in search results
+    "dist": true // set this to false to include "dist" folder in search results
+  },
+  // Turn off tsc task auto detection since we have the necessary tasks as npm scripts
+  "typescript.tsc.autoDetect": "off",
+
+  // Visualize tabs and spaces.
+  "editor.renderWhitespace": "all",
+
+  // Align with the Google's style guide:
+  // https://g3doc.corp.google.com/devtools/editors/vscode/g3doc/setup.md?cl=head
+  "editor.insertSpaces": true,
+  "editor.tabSize": 2,
+  "editor.rulers": [100],
+
+  "files.insertFinalNewline": true,
+  "files.trimTrailingWhitespace": true,
+
+  // Use eslint for linter and code-styler
+  "editor.codeActionsOnSave": {
+    "source.fixAll.eslint": true
+  },
+  // Languages to be validated by eslint on vscode
+  "eslint.validate": [
+    "javascript",
+    "typescript"
+  ]
+}
diff --git a/ide_tooling/cros-ide/.vscode/tasks.json b/ide_tooling/cros-ide/.vscode/tasks.json
new file mode 100644
index 0000000..d7997f7
--- /dev/null
+++ b/ide_tooling/cros-ide/.vscode/tasks.json
@@ -0,0 +1,38 @@
+// See https://go.microsoft.com/fwlink/?LinkId=733558
+// for the documentation about the tasks.json format
+{
+  "version": "2.0.0",
+  "tasks": [
+    {
+      "type": "npm",
+      "script": "compile",
+      "problemMatcher": [
+        "$ts-webpack",
+        "$tslint-webpack"
+      ],
+      "presentation": {
+        "reveal": "never",
+      },
+      "group": {
+        "kind": "build",
+        "isDefault": true
+      }
+    },
+    {
+      "type": "npm",
+      "script": "compile-tests",
+      "presentation": {
+        "reveal": "never",
+      },
+      "group": "build"
+    },
+    {
+      "label": "tasks: compile-tests",
+      "dependsOn": [
+        "npm: compile",
+        "npm: compile-tests"
+      ],
+      "problemMatcher": []
+    }
+  ]
+}
diff --git a/ide_tooling/cros-ide/CHANGELOG.md b/ide_tooling/cros-ide/CHANGELOG.md
new file mode 100644
index 0000000..5bcc9eb
--- /dev/null
+++ b/ide_tooling/cros-ide/CHANGELOG.md
@@ -0,0 +1,9 @@
+# Change Log
+
+All notable changes to the "cros-ide" extension will be documented in this file.
+
+Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
+
+## [Unreleased]
+
+- Initial release
diff --git a/ide_tooling/cros-ide/LICENSE.txt b/ide_tooling/cros-ide/LICENSE.txt
new file mode 100644
index 0000000..1cc39f5
--- /dev/null
+++ b/ide_tooling/cros-ide/LICENSE.txt
@@ -0,0 +1,29 @@
+// Copyright 2022 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/ide_tooling/cros-ide/README.md b/ide_tooling/cros-ide/README.md
new file mode 100644
index 0000000..b3762ea
--- /dev/null
+++ b/ide_tooling/cros-ide/README.md
@@ -0,0 +1,158 @@
+# CrOS IDE
+
+Currently ***EXPERIMENTAL*** and tested only for google internal developers.
+No timely support will be provided.
+
+This plugin consolidates commonly used tools for Chromium OS Development.
+
+## Features
+
+* Autocomplete, x-ref searching, and symbol definition when developing in chroot
+* Managing local and remote DUTs
+* Code health tooling
+
+See [QuickStart Guide] for initial setup.
+
+[QuickStart Guide]: https://chromium.googlesource.com/chromiumos/chromite/+/HEAD/ide_tooling/docs/quickstart.md
+
+## Developers guide
+
+### Initial set up and testing
+
+1. Follow the [QuickStart Guide], skip installing the extension. Open the `cros-ide` directory as
+   your working directory.
+2. Run `npm ci` in the `cros-ide` directory (inside chroot).
+3. *Outside chroot* (open a different terminal), run `npm test` in the `cros-ide` directory to
+   confirm tests pass. `node --version` should return v12.* for the test to pass. If you are using a
+   newer version, please uninstall or downgrade it.
+
+### Testing
+
+There are several ways of testing.
+
+* Testing from GUI
+  * Make sure your VSCode is connected to chroot, and opening `cros-ide` as a
+    workspace.
+  * (See [Debugging the tests] for visual guide)
+    Click the "Run and Debug" icon in the [Activity Bar], select "Run Extension"
+    menu, and click the "Start Debugging" button or press F5. It should launch a new window
+    where the extension built from the source code is installed. Then you can
+    perform whatever manual tests on it. By default, other extensions are disabled. To keep other
+    extensions running, choose "Run Extension (keep other extensions running)".
+  * Similarly, you can select "Extension Tests" instead of "Run Extensions" to run all the tests.
+    The output will be shown in the Debug Console in the IDE used to develop the extension
+* Testing from command line
+  * `npm run unit-test` runs unit tests.
+  * `npm run test` runs all the tests. It must be run outside chroot.
+
+[Activity Bar]: https://code.visualstudio.com/api/references/extension-guidelines#view-containers
+[Debugging the tests]: https://code.visualstudio.com/api/working-with-extensions/testing-extension#debugging-the-tests
+
+### Publishing the extension
+
+Here is the steps to release a new version of a package file, to be installed by all users by
+`./install.sh`.
+
+1. Upload a patch that updates the version in `package.json`, have it reviewed, approved and merged
+   to `cros/main` (for example, http://crrev.com/c/3474259)
+2. Check out that commit in the local git checkout.
+3. Inside chroot, run `./install.sh --upload`. It will build the extension and upload it to Cloud
+   Storage under [chromeos-velocity].
+
+[chromeos-velocity]: https://pantheon.corp.google.com/storage/browser?project=google.com:chromeos-velocity
+
+### FAQs
+
+* How to check that my VSCode is connected to chroot?
+  * In the lower left corner, it should show `SSH: cros` if you followed
+    [QuickStart Guide].
+* How to build and install the extension from local source code?
+  * Run `./install.sh --dev` in the terminal of the VSCode connected to chroot.
+    It builds from the source code and installs it to the current vscode.
+* Why repo upload is slow?
+  * It runs `npm test`. It's a tentative alternative for a CQ which is under
+    construction.
+
+## Requirements
+
+TBD
+
+## Extension Settings
+
+## Known Issues
+
+## Release Notes
+
+Users appreciate release notes as you update your extension.
+
+### 1.0.0
+
+TBD
+
+-----------------------------------------------------------------------------------------------------------
+## Sticky Notes
+
+* [Extension Guidelines](https://code.visualstudio.com/api/references/extension-guidelines)
+* [Project Documentation (Google Internal)](http://go/cros-cowabunga)
+
+-----------------------------------------------------------------------------------------------------------
+## Dependencies
+
+*Important:* Keep this updated and ensure that unrestrictive
+licenses are used
+
+Name: definitely-typed\
+URL: https://github.com/DefinitelyTyped/DefinitelyTyped\
+Remarks: Pulls in TS data-types published via DefinitelyTyped (i.e. @types/*)\
+License: MIT
+
+Name: typescript-eslint\
+URL: https://github.com/typescript-eslint/typescript-eslint/\
+Remarks:\
+License: BSD-2-Clause
+
+Name: eslint\
+URL: https://github.com/eslint/eslint\
+Remarks:\
+License: MIT
+
+Name: eslint-config-google\
+URL: https://github.com/google/eslint-config-google\
+Remarks:\
+License: Apache-2.0
+
+Name: glob\
+URL: https://github.com/isaacs/node-glob\
+Remarks: Unrestrictive license along the lines of MIT\
+Used for unit-tests\
+License: ISC
+
+Name: Typescript\
+URL: https://github.com/microsoft/TypeScript\
+Remarks:\
+License: Apache-2.0
+
+Name: mocha\
+URL: https://github.com/mochajs/mocha\
+Remarks:\
+License: MIT
+
+Name: ts-loader\
+URL: https://github.com/TypeStrong/ts-loader\
+Remarks:\
+License: MIT
+
+Name: webpack\
+URL: https://github.com/webpack/webpack\
+Remarks:\
+License: MIT
+
+Name: webpack-cli\
+URL: https://github.com/webpack/webpack-cli\
+Remarks:\
+License: MIT
+
+Name: webpack\
+URL: https://github.com/Microsoft/vscode-test\
+Remarks:\
+License: MIT
diff --git a/ide_tooling/cros-ide/install.sh b/ide_tooling/cros-ide/install.sh
new file mode 100755
index 0000000..4944779
--- /dev/null
+++ b/ide_tooling/cros-ide/install.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+# Copyright 2022 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+cd "$(dirname "$0")" || exit 1
+
+npm list typescript || npm install typescript
+npx ts-node ./src/tools/install.ts "$@"
diff --git a/ide_tooling/cros-ide/media/README.md b/ide_tooling/cros-ide/media/README.md
new file mode 100644
index 0000000..6029a62
--- /dev/null
+++ b/ide_tooling/cros-ide/media/README.md
@@ -0,0 +1 @@
+cros-device.svg: https://icons.corp.google.com/?selected=Google%20Symbols%3Adevices%3A
diff --git a/ide_tooling/cros-ide/media/cros-device.svg b/ide_tooling/cros-ide/media/cros-device.svg
new file mode 100644
index 0000000..66044a6
--- /dev/null
+++ b/ide_tooling/cros-ide/media/cros-device.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="24px.0" version="1.1" width="24px.0" fill="#041E49"><path d="M2.0 20.0V17.0H4.0V6.0Q4.0 5.175 4.5875 4.5875Q5.175 4.0 6.0 4.0H21.0V6.0H6.0Q6.0 6.0 6.0 6.0Q6.0 6.0 6.0 6.0V17.0H12.0V20.0ZM15.0 20.0Q14.575 20.0 14.2875 19.7125Q14.0 19.425 14.0 19.0V9.0Q14.0 8.575 14.2875 8.2875Q14.575 8.0 15.0 8.0H21.0Q21.425 8.0 21.7125 8.2875Q22.0 8.575 22.0 9.0V19.0Q22.0 19.425 21.7125 19.7125Q21.425 20.0 21.0 20.0ZM16.0 17.0H20.0V10.0H16.0Z" /></svg>
\ No newline at end of file
diff --git a/ide_tooling/cros-ide/package-lock.json b/ide_tooling/cros-ide/package-lock.json
new file mode 100644
index 0000000..3f1d79d
--- /dev/null
+++ b/ide_tooling/cros-ide/package-lock.json
@@ -0,0 +1,4136 @@
+{
+  "name": "cros-ide",
+  "version": "0.0.2",
+  "lockfileVersion": 1,
+  "requires": true,
+  "dependencies": {
+    "@babel/code-frame": {
+      "version": "7.12.11",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
+      "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==",
+      "dev": true,
+      "requires": {
+        "@babel/highlight": "^7.10.4"
+      }
+    },
+    "@babel/helper-validator-identifier": {
+      "version": "7.16.7",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz",
+      "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==",
+      "dev": true
+    },
+    "@babel/highlight": {
+      "version": "7.16.10",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz",
+      "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-validator-identifier": "^7.16.7",
+        "chalk": "^2.0.0",
+        "js-tokens": "^4.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "3.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^1.9.0"
+          }
+        },
+        "chalk": {
+          "version": "2.4.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^3.2.1",
+            "escape-string-regexp": "^1.0.5",
+            "supports-color": "^5.3.0"
+          }
+        },
+        "color-convert": {
+          "version": "1.9.3",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+          "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+          "dev": true,
+          "requires": {
+            "color-name": "1.1.3"
+          }
+        },
+        "color-name": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "dev": true
+        },
+        "escape-string-regexp": {
+          "version": "1.0.5",
+          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+          "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+          "dev": true
+        },
+        "has-flag": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "5.5.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        }
+      }
+    },
+    "@eslint/eslintrc": {
+      "version": "0.4.3",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz",
+      "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==",
+      "dev": true,
+      "requires": {
+        "ajv": "^6.12.4",
+        "debug": "^4.1.1",
+        "espree": "^7.3.0",
+        "globals": "^13.9.0",
+        "ignore": "^4.0.6",
+        "import-fresh": "^3.2.1",
+        "js-yaml": "^3.13.1",
+        "minimatch": "^3.0.4",
+        "strip-json-comments": "^3.1.1"
+      },
+      "dependencies": {
+        "argparse": {
+          "version": "1.0.10",
+          "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+          "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+          "dev": true,
+          "requires": {
+            "sprintf-js": "~1.0.2"
+          }
+        },
+        "ignore": {
+          "version": "4.0.6",
+          "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+          "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
+          "dev": true
+        },
+        "js-yaml": {
+          "version": "3.14.1",
+          "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+          "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+          "dev": true,
+          "requires": {
+            "argparse": "^1.0.7",
+            "esprima": "^4.0.0"
+          }
+        }
+      }
+    },
+    "@humanwhocodes/config-array": {
+      "version": "0.5.0",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz",
+      "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==",
+      "dev": true,
+      "requires": {
+        "@humanwhocodes/object-schema": "^1.2.0",
+        "debug": "^4.1.1",
+        "minimatch": "^3.0.4"
+      }
+    },
+    "@humanwhocodes/object-schema": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
+      "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
+      "dev": true
+    },
+    "@nodelib/fs.scandir": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+      "dev": true,
+      "requires": {
+        "@nodelib/fs.stat": "2.0.5",
+        "run-parallel": "^1.1.9"
+      }
+    },
+    "@nodelib/fs.stat": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+      "dev": true
+    },
+    "@nodelib/fs.walk": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+      "dev": true,
+      "requires": {
+        "@nodelib/fs.scandir": "2.1.5",
+        "fastq": "^1.6.0"
+      }
+    },
+    "@tootallnate/once": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
+      "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
+      "dev": true
+    },
+    "@types/eslint": {
+      "version": "8.4.1",
+      "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz",
+      "integrity": "sha512-GE44+DNEyxxh2Kc6ro/VkIj+9ma0pO0bwv9+uHSyBrikYOHr8zYcdPvnBOp1aw8s+CjRvuSx7CyWqRrNFQ59mA==",
+      "dev": true,
+      "requires": {
+        "@types/estree": "*",
+        "@types/json-schema": "*"
+      }
+    },
+    "@types/eslint-scope": {
+      "version": "3.7.3",
+      "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz",
+      "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==",
+      "dev": true,
+      "requires": {
+        "@types/eslint": "*",
+        "@types/estree": "*"
+      }
+    },
+    "@types/estree": {
+      "version": "0.0.45",
+      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.45.tgz",
+      "integrity": "sha512-jnqIUKDUqJbDIUxm0Uj7bnlMnRm1T/eZ9N+AVMqhPgzrba2GhGG5o/jCTwmdPK709nEZsGoMzXEDUjcXHa3W0g==",
+      "dev": true
+    },
+    "@types/glob": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz",
+      "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==",
+      "dev": true,
+      "requires": {
+        "@types/minimatch": "*",
+        "@types/node": "*"
+      }
+    },
+    "@types/json-schema": {
+      "version": "7.0.9",
+      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
+      "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==",
+      "dev": true
+    },
+    "@types/minimatch": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz",
+      "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==",
+      "dev": true
+    },
+    "@types/mocha": {
+      "version": "9.1.0",
+      "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.0.tgz",
+      "integrity": "sha512-QCWHkbMv4Y5U9oW10Uxbr45qMMSzl4OzijsozynUAgx3kEHUdXB00udx2dWDQ7f2TU2a2uuiFaRZjCe3unPpeg==",
+      "dev": true
+    },
+    "@types/node": {
+      "version": "12.20.42",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.42.tgz",
+      "integrity": "sha512-aI3/oo5DzyiI5R/xAhxxRzfZlWlsbbqdgxfTPkqu/Zt+23GXiJvMCyPJT4+xKSXOnLqoL8jJYMLTwvK2M3a5hw==",
+      "dev": true
+    },
+    "@types/vscode": {
+      "version": "1.63.1",
+      "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.63.1.tgz",
+      "integrity": "sha512-Z+ZqjRcnGfHP86dvx/BtSwWyZPKQ/LBdmAVImY82TphyjOw2KgTKcp7Nx92oNwCTsHzlshwexAG/WiY2JuUm3g==",
+      "dev": true
+    },
+    "@typescript-eslint/eslint-plugin": {
+      "version": "5.10.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.10.1.tgz",
+      "integrity": "sha512-xN3CYqFlyE/qOcy978/L0xLR2HlcAGIyIK5sMOasxaaAPfQRj/MmMV6OC3I7NZO84oEUdWCOju34Z9W8E0pFDQ==",
+      "dev": true,
+      "requires": {
+        "@typescript-eslint/scope-manager": "5.10.1",
+        "@typescript-eslint/type-utils": "5.10.1",
+        "@typescript-eslint/utils": "5.10.1",
+        "debug": "^4.3.2",
+        "functional-red-black-tree": "^1.0.1",
+        "ignore": "^5.1.8",
+        "regexpp": "^3.2.0",
+        "semver": "^7.3.5",
+        "tsutils": "^3.21.0"
+      }
+    },
+    "@typescript-eslint/parser": {
+      "version": "5.10.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.10.1.tgz",
+      "integrity": "sha512-GReo3tjNBwR5RnRO0K2wDIDN31cM3MmDtgyQ85oAxAmC5K3j/g85IjP+cDfcqDsDDBf1HNKQAD0WqOYL8jXqUA==",
+      "dev": true,
+      "requires": {
+        "@typescript-eslint/scope-manager": "5.10.1",
+        "@typescript-eslint/types": "5.10.1",
+        "@typescript-eslint/typescript-estree": "5.10.1",
+        "debug": "^4.3.2"
+      }
+    },
+    "@typescript-eslint/scope-manager": {
+      "version": "5.10.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.10.1.tgz",
+      "integrity": "sha512-Lyvi559Gvpn94k7+ElXNMEnXu/iundV5uFmCUNnftbFrUbAJ1WBoaGgkbOBm07jVZa682oaBU37ao/NGGX4ZDg==",
+      "dev": true,
+      "requires": {
+        "@typescript-eslint/types": "5.10.1",
+        "@typescript-eslint/visitor-keys": "5.10.1"
+      }
+    },
+    "@typescript-eslint/type-utils": {
+      "version": "5.10.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.10.1.tgz",
+      "integrity": "sha512-AfVJkV8uck/UIoDqhu+ptEdBoQATON9GXnhOpPLzkQRJcSChkvD//qsz9JVffl2goxX+ybs5klvacE9vmrQyCw==",
+      "dev": true,
+      "requires": {
+        "@typescript-eslint/utils": "5.10.1",
+        "debug": "^4.3.2",
+        "tsutils": "^3.21.0"
+      }
+    },
+    "@typescript-eslint/types": {
+      "version": "5.10.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.10.1.tgz",
+      "integrity": "sha512-ZvxQ2QMy49bIIBpTqFiOenucqUyjTQ0WNLhBM6X1fh1NNlYAC6Kxsx8bRTY3jdYsYg44a0Z/uEgQkohbR0H87Q==",
+      "dev": true
+    },
+    "@typescript-eslint/typescript-estree": {
+      "version": "5.10.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.10.1.tgz",
+      "integrity": "sha512-PwIGnH7jIueXv4opcwEbVGDATjGPO1dx9RkUl5LlHDSe+FXxPwFL5W/qYd5/NHr7f6lo/vvTrAzd0KlQtRusJQ==",
+      "dev": true,
+      "requires": {
+        "@typescript-eslint/types": "5.10.1",
+        "@typescript-eslint/visitor-keys": "5.10.1",
+        "debug": "^4.3.2",
+        "globby": "^11.0.4",
+        "is-glob": "^4.0.3",
+        "semver": "^7.3.5",
+        "tsutils": "^3.21.0"
+      }
+    },
+    "@typescript-eslint/utils": {
+      "version": "5.10.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.10.1.tgz",
+      "integrity": "sha512-RRmlITiUbLuTRtn/gcPRi4202niF+q7ylFLCKu4c+O/PcpRvZ/nAUwQ2G00bZgpWkhrNLNnvhZLbDn8Ml0qsQw==",
+      "dev": true,
+      "requires": {
+        "@types/json-schema": "^7.0.9",
+        "@typescript-eslint/scope-manager": "5.10.1",
+        "@typescript-eslint/types": "5.10.1",
+        "@typescript-eslint/typescript-estree": "5.10.1",
+        "eslint-scope": "^5.1.1",
+        "eslint-utils": "^3.0.0"
+      }
+    },
+    "@typescript-eslint/visitor-keys": {
+      "version": "5.10.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.10.1.tgz",
+      "integrity": "sha512-NjQ0Xinhy9IL979tpoTRuLKxMc0zJC7QVSdeerXs2/QvOy2yRkzX5dRb10X5woNUdJgU8G3nYRDlI33sq1K4YQ==",
+      "dev": true,
+      "requires": {
+        "@typescript-eslint/types": "5.10.1",
+        "eslint-visitor-keys": "^3.0.0"
+      }
+    },
+    "@ungap/promise-all-settled": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz",
+      "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==",
+      "dev": true
+    },
+    "@vscode/test-electron": {
+      "version": "1.6.2",
+      "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-1.6.2.tgz",
+      "integrity": "sha512-W01ajJEMx6223Y7J5yaajGjVs1QfW3YGkkOJHVKfAMEqNB1ZHN9wCcViehv5ZwVSSJnjhu6lYEYgwBdHtCxqhQ==",
+      "dev": true,
+      "requires": {
+        "http-proxy-agent": "^4.0.1",
+        "https-proxy-agent": "^5.0.0",
+        "rimraf": "^3.0.2",
+        "unzipper": "^0.10.11"
+      }
+    },
+    "@webassemblyjs/ast": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz",
+      "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==",
+      "dev": true,
+      "requires": {
+        "@webassemblyjs/helper-module-context": "1.9.0",
+        "@webassemblyjs/helper-wasm-bytecode": "1.9.0",
+        "@webassemblyjs/wast-parser": "1.9.0"
+      }
+    },
+    "@webassemblyjs/floating-point-hex-parser": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz",
+      "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==",
+      "dev": true
+    },
+    "@webassemblyjs/helper-api-error": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz",
+      "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==",
+      "dev": true
+    },
+    "@webassemblyjs/helper-buffer": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz",
+      "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==",
+      "dev": true
+    },
+    "@webassemblyjs/helper-code-frame": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz",
+      "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==",
+      "dev": true,
+      "requires": {
+        "@webassemblyjs/wast-printer": "1.9.0"
+      }
+    },
+    "@webassemblyjs/helper-fsm": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz",
+      "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==",
+      "dev": true
+    },
+    "@webassemblyjs/helper-module-context": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz",
+      "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==",
+      "dev": true,
+      "requires": {
+        "@webassemblyjs/ast": "1.9.0"
+      }
+    },
+    "@webassemblyjs/helper-wasm-bytecode": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz",
+      "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==",
+      "dev": true
+    },
+    "@webassemblyjs/helper-wasm-section": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz",
+      "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==",
+      "dev": true,
+      "requires": {
+        "@webassemblyjs/ast": "1.9.0",
+        "@webassemblyjs/helper-buffer": "1.9.0",
+        "@webassemblyjs/helper-wasm-bytecode": "1.9.0",
+        "@webassemblyjs/wasm-gen": "1.9.0"
+      }
+    },
+    "@webassemblyjs/ieee754": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz",
+      "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==",
+      "dev": true,
+      "requires": {
+        "@xtuc/ieee754": "^1.2.0"
+      }
+    },
+    "@webassemblyjs/leb128": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz",
+      "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==",
+      "dev": true,
+      "requires": {
+        "@xtuc/long": "4.2.2"
+      }
+    },
+    "@webassemblyjs/utf8": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz",
+      "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==",
+      "dev": true
+    },
+    "@webassemblyjs/wasm-edit": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz",
+      "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==",
+      "dev": true,
+      "requires": {
+        "@webassemblyjs/ast": "1.9.0",
+        "@webassemblyjs/helper-buffer": "1.9.0",
+        "@webassemblyjs/helper-wasm-bytecode": "1.9.0",
+        "@webassemblyjs/helper-wasm-section": "1.9.0",
+        "@webassemblyjs/wasm-gen": "1.9.0",
+        "@webassemblyjs/wasm-opt": "1.9.0",
+        "@webassemblyjs/wasm-parser": "1.9.0",
+        "@webassemblyjs/wast-printer": "1.9.0"
+      }
+    },
+    "@webassemblyjs/wasm-gen": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz",
+      "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==",
+      "dev": true,
+      "requires": {
+        "@webassemblyjs/ast": "1.9.0",
+        "@webassemblyjs/helper-wasm-bytecode": "1.9.0",
+        "@webassemblyjs/ieee754": "1.9.0",
+        "@webassemblyjs/leb128": "1.9.0",
+        "@webassemblyjs/utf8": "1.9.0"
+      }
+    },
+    "@webassemblyjs/wasm-opt": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz",
+      "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==",
+      "dev": true,
+      "requires": {
+        "@webassemblyjs/ast": "1.9.0",
+        "@webassemblyjs/helper-buffer": "1.9.0",
+        "@webassemblyjs/wasm-gen": "1.9.0",
+        "@webassemblyjs/wasm-parser": "1.9.0"
+      }
+    },
+    "@webassemblyjs/wasm-parser": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz",
+      "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==",
+      "dev": true,
+      "requires": {
+        "@webassemblyjs/ast": "1.9.0",
+        "@webassemblyjs/helper-api-error": "1.9.0",
+        "@webassemblyjs/helper-wasm-bytecode": "1.9.0",
+        "@webassemblyjs/ieee754": "1.9.0",
+        "@webassemblyjs/leb128": "1.9.0",
+        "@webassemblyjs/utf8": "1.9.0"
+      }
+    },
+    "@webassemblyjs/wast-parser": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz",
+      "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==",
+      "dev": true,
+      "requires": {
+        "@webassemblyjs/ast": "1.9.0",
+        "@webassemblyjs/floating-point-hex-parser": "1.9.0",
+        "@webassemblyjs/helper-api-error": "1.9.0",
+        "@webassemblyjs/helper-code-frame": "1.9.0",
+        "@webassemblyjs/helper-fsm": "1.9.0",
+        "@xtuc/long": "4.2.2"
+      }
+    },
+    "@webassemblyjs/wast-printer": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz",
+      "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==",
+      "dev": true,
+      "requires": {
+        "@webassemblyjs/ast": "1.9.0",
+        "@webassemblyjs/wast-parser": "1.9.0",
+        "@xtuc/long": "4.2.2"
+      }
+    },
+    "@xtuc/ieee754": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
+      "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
+      "dev": true
+    },
+    "@xtuc/long": {
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
+      "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
+      "dev": true
+    },
+    "acorn": {
+      "version": "8.7.0",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz",
+      "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==",
+      "dev": true
+    },
+    "acorn-jsx": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+      "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+      "dev": true
+    },
+    "agent-base": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
+      "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+      "dev": true,
+      "requires": {
+        "debug": "4"
+      }
+    },
+    "ajv": {
+      "version": "6.12.6",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+      "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+      "dev": true,
+      "requires": {
+        "fast-deep-equal": "^3.1.1",
+        "fast-json-stable-stringify": "^2.0.0",
+        "json-schema-traverse": "^0.4.1",
+        "uri-js": "^4.2.2"
+      }
+    },
+    "ajv-keywords": {
+      "version": "3.5.2",
+      "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
+      "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
+      "dev": true
+    },
+    "ansi-colors": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
+      "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
+      "dev": true
+    },
+    "ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true
+    },
+    "ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "requires": {
+        "color-convert": "^2.0.1"
+      }
+    },
+    "anymatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
+      "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
+      "dev": true,
+      "requires": {
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
+      }
+    },
+    "argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+      "dev": true
+    },
+    "arr-diff": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+      "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
+      "dev": true
+    },
+    "arr-flatten": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+      "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+      "dev": true
+    },
+    "arr-union": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+      "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
+      "dev": true
+    },
+    "array-union": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+      "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+      "dev": true
+    },
+    "array-unique": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+      "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
+      "dev": true
+    },
+    "assign-symbols": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+      "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
+      "dev": true
+    },
+    "astral-regex": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
+      "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
+      "dev": true
+    },
+    "atob": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+      "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+      "dev": true
+    },
+    "balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+      "dev": true
+    },
+    "base": {
+      "version": "0.11.2",
+      "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+      "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
+      "dev": true,
+      "requires": {
+        "cache-base": "^1.0.1",
+        "class-utils": "^0.3.5",
+        "component-emitter": "^1.2.1",
+        "define-property": "^1.0.0",
+        "isobject": "^3.0.1",
+        "mixin-deep": "^1.2.0",
+        "pascalcase": "^0.1.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^1.0.0"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        }
+      }
+    },
+    "big-integer": {
+      "version": "1.6.51",
+      "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
+      "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==",
+      "dev": true
+    },
+    "big.js": {
+      "version": "5.2.2",
+      "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
+      "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
+      "dev": true
+    },
+    "binary": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz",
+      "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=",
+      "dev": true,
+      "requires": {
+        "buffers": "~0.1.1",
+        "chainsaw": "~0.1.0"
+      }
+    },
+    "binary-extensions": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+      "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+      "dev": true
+    },
+    "bluebird": {
+      "version": "3.4.7",
+      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz",
+      "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=",
+      "dev": true
+    },
+    "brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
+      "requires": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "braces": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+      "dev": true,
+      "requires": {
+        "fill-range": "^7.0.1"
+      }
+    },
+    "browser-stdout": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
+      "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
+      "dev": true
+    },
+    "browserslist": {
+      "version": "4.19.1",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz",
+      "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==",
+      "dev": true,
+      "requires": {
+        "caniuse-lite": "^1.0.30001286",
+        "electron-to-chromium": "^1.4.17",
+        "escalade": "^3.1.1",
+        "node-releases": "^2.0.1",
+        "picocolors": "^1.0.0"
+      }
+    },
+    "buffer-from": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+      "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+      "dev": true
+    },
+    "buffer-indexof-polyfill": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz",
+      "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==",
+      "dev": true
+    },
+    "buffers": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz",
+      "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=",
+      "dev": true
+    },
+    "cache-base": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+      "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
+      "dev": true,
+      "requires": {
+        "collection-visit": "^1.0.0",
+        "component-emitter": "^1.2.1",
+        "get-value": "^2.0.6",
+        "has-value": "^1.0.0",
+        "isobject": "^3.0.1",
+        "set-value": "^2.0.0",
+        "to-object-path": "^0.3.0",
+        "union-value": "^1.0.0",
+        "unset-value": "^1.0.0"
+      }
+    },
+    "callsites": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+      "dev": true
+    },
+    "camelcase": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+      "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+      "dev": true
+    },
+    "caniuse-lite": {
+      "version": "1.0.30001302",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001302.tgz",
+      "integrity": "sha512-YYTMO+tfwvgUN+1ZnRViE53Ma1S/oETg+J2lISsqi/ZTNThj3ZYBOKP2rHwJc37oCsPqAzJ3w2puZHn0xlLPPw==",
+      "dev": true
+    },
+    "chainsaw": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz",
+      "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=",
+      "dev": true,
+      "requires": {
+        "traverse": ">=0.3.0 <0.4"
+      }
+    },
+    "chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "requires": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      }
+    },
+    "chokidar": {
+      "version": "3.5.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+      "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+      "dev": true,
+      "requires": {
+        "anymatch": "~3.1.2",
+        "braces": "~3.0.2",
+        "fsevents": "~2.3.2",
+        "glob-parent": "~5.1.2",
+        "is-binary-path": "~2.1.0",
+        "is-glob": "~4.0.1",
+        "normalize-path": "~3.0.0",
+        "readdirp": "~3.6.0"
+      }
+    },
+    "chrome-trace-event": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
+      "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==",
+      "dev": true
+    },
+    "class-utils": {
+      "version": "0.3.6",
+      "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+      "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
+      "dev": true,
+      "requires": {
+        "arr-union": "^3.1.0",
+        "define-property": "^0.2.5",
+        "isobject": "^3.0.0",
+        "static-extend": "^0.1.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        }
+      }
+    },
+    "cliui": {
+      "version": "7.0.4",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+      "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+      "dev": true,
+      "requires": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.0",
+        "wrap-ansi": "^7.0.0"
+      }
+    },
+    "collection-visit": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+      "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
+      "dev": true,
+      "requires": {
+        "map-visit": "^1.0.0",
+        "object-visit": "^1.0.0"
+      }
+    },
+    "color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "requires": {
+        "color-name": "~1.1.4"
+      }
+    },
+    "color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "commander": {
+      "version": "2.20.3",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+      "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+      "dev": true
+    },
+    "component-emitter": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
+      "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
+      "dev": true
+    },
+    "concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+      "dev": true
+    },
+    "copy-descriptor": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+      "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
+      "dev": true
+    },
+    "core-util-is": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+      "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+      "dev": true
+    },
+    "cross-spawn": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+      "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+      "dev": true,
+      "requires": {
+        "path-key": "^3.1.0",
+        "shebang-command": "^2.0.0",
+        "which": "^2.0.1"
+      }
+    },
+    "debug": {
+      "version": "4.3.3",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
+      "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
+      "dev": true,
+      "requires": {
+        "ms": "2.1.2"
+      }
+    },
+    "decamelize": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
+      "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
+      "dev": true
+    },
+    "decode-uri-component": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
+      "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
+      "dev": true
+    },
+    "deep-is": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+      "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+      "dev": true
+    },
+    "define-property": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+      "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+      "dev": true,
+      "requires": {
+        "is-descriptor": "^1.0.2",
+        "isobject": "^3.0.1"
+      },
+      "dependencies": {
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        }
+      }
+    },
+    "detect-file": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz",
+      "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=",
+      "dev": true
+    },
+    "diff": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
+      "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
+      "dev": true
+    },
+    "dir-glob": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+      "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+      "dev": true,
+      "requires": {
+        "path-type": "^4.0.0"
+      }
+    },
+    "doctrine": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+      "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+      "dev": true,
+      "requires": {
+        "esutils": "^2.0.2"
+      }
+    },
+    "duplexer2": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
+      "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=",
+      "dev": true,
+      "requires": {
+        "readable-stream": "^2.0.2"
+      }
+    },
+    "electron-to-chromium": {
+      "version": "1.4.54",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.54.tgz",
+      "integrity": "sha512-jRAoneRdSxnpRHO0ANpnEUtQHXxlgfVjrLOnQSisw1ryjXJXvS0pJaR/v2B7S++/tRjgEDp4Sjn5nmgb6uTySw==",
+      "dev": true
+    },
+    "emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true
+    },
+    "emojis-list": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
+      "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
+      "dev": true
+    },
+    "enhanced-resolve": {
+      "version": "5.8.3",
+      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz",
+      "integrity": "sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA==",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.2.4",
+        "tapable": "^2.2.0"
+      }
+    },
+    "enquirer": {
+      "version": "2.3.6",
+      "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
+      "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==",
+      "dev": true,
+      "requires": {
+        "ansi-colors": "^4.1.1"
+      }
+    },
+    "errno": {
+      "version": "0.1.8",
+      "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
+      "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
+      "dev": true,
+      "requires": {
+        "prr": "~1.0.1"
+      }
+    },
+    "escalade": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+      "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+      "dev": true
+    },
+    "escape-string-regexp": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+      "dev": true
+    },
+    "eslint": {
+      "version": "7.32.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz",
+      "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==",
+      "dev": true,
+      "requires": {
+        "@babel/code-frame": "7.12.11",
+        "@eslint/eslintrc": "^0.4.3",
+        "@humanwhocodes/config-array": "^0.5.0",
+        "ajv": "^6.10.0",
+        "chalk": "^4.0.0",
+        "cross-spawn": "^7.0.2",
+        "debug": "^4.0.1",
+        "doctrine": "^3.0.0",
+        "enquirer": "^2.3.5",
+        "escape-string-regexp": "^4.0.0",
+        "eslint-scope": "^5.1.1",
+        "eslint-utils": "^2.1.0",
+        "eslint-visitor-keys": "^2.0.0",
+        "espree": "^7.3.1",
+        "esquery": "^1.4.0",
+        "esutils": "^2.0.2",
+        "fast-deep-equal": "^3.1.3",
+        "file-entry-cache": "^6.0.1",
+        "functional-red-black-tree": "^1.0.1",
+        "glob-parent": "^5.1.2",
+        "globals": "^13.6.0",
+        "ignore": "^4.0.6",
+        "import-fresh": "^3.0.0",
+        "imurmurhash": "^0.1.4",
+        "is-glob": "^4.0.0",
+        "js-yaml": "^3.13.1",
+        "json-stable-stringify-without-jsonify": "^1.0.1",
+        "levn": "^0.4.1",
+        "lodash.merge": "^4.6.2",
+        "minimatch": "^3.0.4",
+        "natural-compare": "^1.4.0",
+        "optionator": "^0.9.1",
+        "progress": "^2.0.0",
+        "regexpp": "^3.1.0",
+        "semver": "^7.2.1",
+        "strip-ansi": "^6.0.0",
+        "strip-json-comments": "^3.1.0",
+        "table": "^6.0.9",
+        "text-table": "^0.2.0",
+        "v8-compile-cache": "^2.0.3"
+      },
+      "dependencies": {
+        "argparse": {
+          "version": "1.0.10",
+          "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+          "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+          "dev": true,
+          "requires": {
+            "sprintf-js": "~1.0.2"
+          }
+        },
+        "eslint-utils": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
+          "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
+          "dev": true,
+          "requires": {
+            "eslint-visitor-keys": "^1.1.0"
+          },
+          "dependencies": {
+            "eslint-visitor-keys": {
+              "version": "1.3.0",
+              "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+              "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+              "dev": true
+            }
+          }
+        },
+        "eslint-visitor-keys": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
+          "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
+          "dev": true
+        },
+        "ignore": {
+          "version": "4.0.6",
+          "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+          "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
+          "dev": true
+        },
+        "js-yaml": {
+          "version": "3.14.1",
+          "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+          "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+          "dev": true,
+          "requires": {
+            "argparse": "^1.0.7",
+            "esprima": "^4.0.0"
+          }
+        }
+      }
+    },
+    "eslint-config-google": {
+      "version": "0.14.0",
+      "resolved": "https://registry.npmjs.org/eslint-config-google/-/eslint-config-google-0.14.0.tgz",
+      "integrity": "sha512-WsbX4WbjuMvTdeVL6+J3rK1RGhCTqjsFjX7UMSMgZiyxxaNLkoJENbrGExzERFeoTpGw3F3FypTiWAP9ZXzkEw==",
+      "dev": true
+    },
+    "eslint-scope": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+      "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+      "dev": true,
+      "requires": {
+        "esrecurse": "^4.3.0",
+        "estraverse": "^4.1.1"
+      }
+    },
+    "eslint-utils": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
+      "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
+      "dev": true,
+      "requires": {
+        "eslint-visitor-keys": "^2.0.0"
+      },
+      "dependencies": {
+        "eslint-visitor-keys": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
+          "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
+          "dev": true
+        }
+      }
+    },
+    "eslint-visitor-keys": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.2.0.tgz",
+      "integrity": "sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ==",
+      "dev": true
+    },
+    "espree": {
+      "version": "7.3.1",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz",
+      "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==",
+      "dev": true,
+      "requires": {
+        "acorn": "^7.4.0",
+        "acorn-jsx": "^5.3.1",
+        "eslint-visitor-keys": "^1.3.0"
+      },
+      "dependencies": {
+        "acorn": {
+          "version": "7.4.1",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
+          "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
+          "dev": true
+        },
+        "eslint-visitor-keys": {
+          "version": "1.3.0",
+          "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+          "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+          "dev": true
+        }
+      }
+    },
+    "esprima": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+      "dev": true
+    },
+    "esquery": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
+      "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
+      "dev": true,
+      "requires": {
+        "estraverse": "^5.1.0"
+      },
+      "dependencies": {
+        "estraverse": {
+          "version": "5.3.0",
+          "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+          "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+          "dev": true
+        }
+      }
+    },
+    "esrecurse": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+      "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+      "dev": true,
+      "requires": {
+        "estraverse": "^5.2.0"
+      },
+      "dependencies": {
+        "estraverse": {
+          "version": "5.3.0",
+          "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+          "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+          "dev": true
+        }
+      }
+    },
+    "estraverse": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+      "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+      "dev": true
+    },
+    "esutils": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+      "dev": true
+    },
+    "events": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+      "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+      "dev": true
+    },
+    "expand-brackets": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+      "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+      "dev": true,
+      "requires": {
+        "debug": "^2.3.3",
+        "define-property": "^0.2.5",
+        "extend-shallow": "^2.0.1",
+        "posix-character-classes": "^0.1.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        },
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true
+        }
+      }
+    },
+    "expand-tilde": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
+      "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=",
+      "dev": true,
+      "requires": {
+        "homedir-polyfill": "^1.0.1"
+      }
+    },
+    "extend-shallow": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+      "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
+      "dev": true,
+      "requires": {
+        "assign-symbols": "^1.0.0",
+        "is-extendable": "^1.0.1"
+      },
+      "dependencies": {
+        "is-extendable": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+          "dev": true,
+          "requires": {
+            "is-plain-object": "^2.0.4"
+          }
+        }
+      }
+    },
+    "extglob": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+      "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+      "dev": true,
+      "requires": {
+        "array-unique": "^0.3.2",
+        "define-property": "^1.0.0",
+        "expand-brackets": "^2.1.4",
+        "extend-shallow": "^2.0.1",
+        "fragment-cache": "^0.2.1",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^1.0.0"
+          }
+        },
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        }
+      }
+    },
+    "fast-deep-equal": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+      "dev": true
+    },
+    "fast-glob": {
+      "version": "3.2.11",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz",
+      "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==",
+      "dev": true,
+      "requires": {
+        "@nodelib/fs.stat": "^2.0.2",
+        "@nodelib/fs.walk": "^1.2.3",
+        "glob-parent": "^5.1.2",
+        "merge2": "^1.3.0",
+        "micromatch": "^4.0.4"
+      }
+    },
+    "fast-json-stable-stringify": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+      "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+      "dev": true
+    },
+    "fast-levenshtein": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+      "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
+      "dev": true
+    },
+    "fastq": {
+      "version": "1.13.0",
+      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
+      "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
+      "dev": true,
+      "requires": {
+        "reusify": "^1.0.4"
+      }
+    },
+    "file-entry-cache": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+      "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+      "dev": true,
+      "requires": {
+        "flat-cache": "^3.0.4"
+      }
+    },
+    "fill-range": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+      "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+      "dev": true,
+      "requires": {
+        "to-regex-range": "^5.0.1"
+      }
+    },
+    "find-up": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+      "dev": true,
+      "requires": {
+        "locate-path": "^6.0.0",
+        "path-exists": "^4.0.0"
+      }
+    },
+    "findup-sync": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz",
+      "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==",
+      "dev": true,
+      "requires": {
+        "detect-file": "^1.0.0",
+        "is-glob": "^4.0.0",
+        "micromatch": "^3.0.4",
+        "resolve-dir": "^1.0.1"
+      },
+      "dependencies": {
+        "braces": {
+          "version": "2.3.2",
+          "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+          "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+          "dev": true,
+          "requires": {
+            "arr-flatten": "^1.1.0",
+            "array-unique": "^0.3.2",
+            "extend-shallow": "^2.0.1",
+            "fill-range": "^4.0.0",
+            "isobject": "^3.0.1",
+            "repeat-element": "^1.1.2",
+            "snapdragon": "^0.8.1",
+            "snapdragon-node": "^2.0.1",
+            "split-string": "^3.0.2",
+            "to-regex": "^3.0.1"
+          },
+          "dependencies": {
+            "extend-shallow": {
+              "version": "2.0.1",
+              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+              "dev": true,
+              "requires": {
+                "is-extendable": "^0.1.0"
+              }
+            }
+          }
+        },
+        "fill-range": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+          "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+          "dev": true,
+          "requires": {
+            "extend-shallow": "^2.0.1",
+            "is-number": "^3.0.0",
+            "repeat-string": "^1.6.1",
+            "to-regex-range": "^2.1.0"
+          },
+          "dependencies": {
+            "extend-shallow": {
+              "version": "2.0.1",
+              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+              "dev": true,
+              "requires": {
+                "is-extendable": "^0.1.0"
+              }
+            }
+          }
+        },
+        "is-number": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+          "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+          "dev": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "3.2.2",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+              "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+              "dev": true,
+              "requires": {
+                "is-buffer": "^1.1.5"
+              }
+            }
+          }
+        },
+        "micromatch": {
+          "version": "3.1.10",
+          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+          "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+          "dev": true,
+          "requires": {
+            "arr-diff": "^4.0.0",
+            "array-unique": "^0.3.2",
+            "braces": "^2.3.1",
+            "define-property": "^2.0.2",
+            "extend-shallow": "^3.0.2",
+            "extglob": "^2.0.4",
+            "fragment-cache": "^0.2.1",
+            "kind-of": "^6.0.2",
+            "nanomatch": "^1.2.9",
+            "object.pick": "^1.3.0",
+            "regex-not": "^1.0.0",
+            "snapdragon": "^0.8.1",
+            "to-regex": "^3.0.2"
+          }
+        },
+        "to-regex-range": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+          "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
+          "dev": true,
+          "requires": {
+            "is-number": "^3.0.0",
+            "repeat-string": "^1.6.1"
+          }
+        }
+      }
+    },
+    "flat": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
+      "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
+      "dev": true
+    },
+    "flat-cache": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
+      "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
+      "dev": true,
+      "requires": {
+        "flatted": "^3.1.0",
+        "rimraf": "^3.0.2"
+      }
+    },
+    "flatted": {
+      "version": "3.2.5",
+      "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz",
+      "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==",
+      "dev": true
+    },
+    "for-in": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+      "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
+      "dev": true
+    },
+    "fragment-cache": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+      "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
+      "dev": true,
+      "requires": {
+        "map-cache": "^0.2.2"
+      }
+    },
+    "fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+      "dev": true
+    },
+    "fsevents": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+      "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+      "dev": true,
+      "optional": true
+    },
+    "fstream": {
+      "version": "1.0.12",
+      "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
+      "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.1.2",
+        "inherits": "~2.0.0",
+        "mkdirp": ">=0.5 0",
+        "rimraf": "2"
+      },
+      "dependencies": {
+        "rimraf": {
+          "version": "2.7.1",
+          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+          "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+          "dev": true,
+          "requires": {
+            "glob": "^7.1.3"
+          }
+        }
+      }
+    },
+    "functional-red-black-tree": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
+      "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
+      "dev": true
+    },
+    "get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "dev": true
+    },
+    "get-value": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+      "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
+      "dev": true
+    },
+    "glob": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
+      "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
+      "dev": true,
+      "requires": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.0.4",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      }
+    },
+    "glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "dev": true,
+      "requires": {
+        "is-glob": "^4.0.1"
+      }
+    },
+    "glob-to-regexp": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
+      "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
+      "dev": true
+    },
+    "global-modules": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz",
+      "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==",
+      "dev": true,
+      "requires": {
+        "global-prefix": "^3.0.0"
+      },
+      "dependencies": {
+        "global-prefix": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz",
+          "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==",
+          "dev": true,
+          "requires": {
+            "ini": "^1.3.5",
+            "kind-of": "^6.0.2",
+            "which": "^1.3.1"
+          }
+        },
+        "which": {
+          "version": "1.3.1",
+          "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+          "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+          "dev": true,
+          "requires": {
+            "isexe": "^2.0.0"
+          }
+        }
+      }
+    },
+    "global-prefix": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz",
+      "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=",
+      "dev": true,
+      "requires": {
+        "expand-tilde": "^2.0.2",
+        "homedir-polyfill": "^1.0.1",
+        "ini": "^1.3.4",
+        "is-windows": "^1.0.1",
+        "which": "^1.2.14"
+      },
+      "dependencies": {
+        "which": {
+          "version": "1.3.1",
+          "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+          "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+          "dev": true,
+          "requires": {
+            "isexe": "^2.0.0"
+          }
+        }
+      }
+    },
+    "globals": {
+      "version": "13.12.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz",
+      "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==",
+      "dev": true,
+      "requires": {
+        "type-fest": "^0.20.2"
+      }
+    },
+    "globby": {
+      "version": "11.1.0",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+      "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+      "dev": true,
+      "requires": {
+        "array-union": "^2.1.0",
+        "dir-glob": "^3.0.1",
+        "fast-glob": "^3.2.9",
+        "ignore": "^5.2.0",
+        "merge2": "^1.4.1",
+        "slash": "^3.0.0"
+      }
+    },
+    "graceful-fs": {
+      "version": "4.2.9",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
+      "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==",
+      "dev": true
+    },
+    "growl": {
+      "version": "1.10.5",
+      "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
+      "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==",
+      "dev": true
+    },
+    "has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true
+    },
+    "has-value": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+      "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
+      "dev": true,
+      "requires": {
+        "get-value": "^2.0.6",
+        "has-values": "^1.0.0",
+        "isobject": "^3.0.0"
+      }
+    },
+    "has-values": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
+      "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
+      "dev": true,
+      "requires": {
+        "is-number": "^3.0.0",
+        "kind-of": "^4.0.0"
+      },
+      "dependencies": {
+        "is-number": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+          "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+          "dev": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "3.2.2",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+              "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+              "dev": true,
+              "requires": {
+                "is-buffer": "^1.1.5"
+              }
+            }
+          }
+        },
+        "kind-of": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+          "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "he": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+      "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+      "dev": true
+    },
+    "homedir-polyfill": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
+      "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
+      "dev": true,
+      "requires": {
+        "parse-passwd": "^1.0.0"
+      }
+    },
+    "http-proxy-agent": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
+      "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==",
+      "dev": true,
+      "requires": {
+        "@tootallnate/once": "1",
+        "agent-base": "6",
+        "debug": "4"
+      }
+    },
+    "https-proxy-agent": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
+      "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==",
+      "dev": true,
+      "requires": {
+        "agent-base": "6",
+        "debug": "4"
+      }
+    },
+    "ignore": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
+      "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==",
+      "dev": true
+    },
+    "import-fresh": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+      "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+      "dev": true,
+      "requires": {
+        "parent-module": "^1.0.0",
+        "resolve-from": "^4.0.0"
+      }
+    },
+    "import-local": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz",
+      "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==",
+      "dev": true,
+      "requires": {
+        "pkg-dir": "^3.0.0",
+        "resolve-cwd": "^2.0.0"
+      },
+      "dependencies": {
+        "find-up": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+          "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+          "dev": true,
+          "requires": {
+            "locate-path": "^3.0.0"
+          }
+        },
+        "locate-path": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+          "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+          "dev": true,
+          "requires": {
+            "p-locate": "^3.0.0",
+            "path-exists": "^3.0.0"
+          }
+        },
+        "p-limit": {
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+          "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+          "dev": true,
+          "requires": {
+            "p-try": "^2.0.0"
+          }
+        },
+        "p-locate": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+          "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+          "dev": true,
+          "requires": {
+            "p-limit": "^2.0.0"
+          }
+        },
+        "path-exists": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+          "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+          "dev": true
+        },
+        "pkg-dir": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz",
+          "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==",
+          "dev": true,
+          "requires": {
+            "find-up": "^3.0.0"
+          }
+        }
+      }
+    },
+    "imurmurhash": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+      "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
+      "dev": true
+    },
+    "inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+      "dev": true,
+      "requires": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+      "dev": true
+    },
+    "ini": {
+      "version": "1.3.8",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+      "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+      "dev": true
+    },
+    "interpret": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
+      "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
+      "dev": true
+    },
+    "is-accessor-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+      "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.0.2"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "is-binary-path": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+      "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+      "dev": true,
+      "requires": {
+        "binary-extensions": "^2.0.0"
+      }
+    },
+    "is-buffer": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+      "dev": true
+    },
+    "is-data-descriptor": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+      "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.0.2"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "is-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+      "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+      "dev": true,
+      "requires": {
+        "is-accessor-descriptor": "^0.1.6",
+        "is-data-descriptor": "^0.1.4",
+        "kind-of": "^5.0.0"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+          "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+          "dev": true
+        }
+      }
+    },
+    "is-extendable": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+      "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
+      "dev": true
+    },
+    "is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+      "dev": true
+    },
+    "is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+      "dev": true
+    },
+    "is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+      "dev": true,
+      "requires": {
+        "is-extglob": "^2.1.1"
+      }
+    },
+    "is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "dev": true
+    },
+    "is-plain-obj": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
+      "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
+      "dev": true
+    },
+    "is-plain-object": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+      "dev": true,
+      "requires": {
+        "isobject": "^3.0.1"
+      }
+    },
+    "is-unicode-supported": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+      "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+      "dev": true
+    },
+    "is-windows": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+      "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+      "dev": true
+    },
+    "isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+      "dev": true
+    },
+    "isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+      "dev": true
+    },
+    "isobject": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+      "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+      "dev": true
+    },
+    "jest-worker": {
+      "version": "27.4.6",
+      "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.6.tgz",
+      "integrity": "sha512-gHWJF/6Xi5CTG5QCvROr6GcmpIqNYpDJyc8A1h/DyXqH1tD6SnRCM0d3U5msV31D2LB/U+E0M+W4oyvKV44oNw==",
+      "dev": true,
+      "requires": {
+        "@types/node": "*",
+        "merge-stream": "^2.0.0",
+        "supports-color": "^8.0.0"
+      },
+      "dependencies": {
+        "supports-color": {
+          "version": "8.1.1",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+          "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+      "dev": true
+    },
+    "js-yaml": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+      "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+      "dev": true,
+      "requires": {
+        "argparse": "^2.0.1"
+      }
+    },
+    "json-parse-better-errors": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
+      "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
+      "dev": true
+    },
+    "json-schema-traverse": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+      "dev": true
+    },
+    "json-stable-stringify-without-jsonify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+      "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
+      "dev": true
+    },
+    "json5": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
+      "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
+      "dev": true,
+      "requires": {
+        "minimist": "^1.2.0"
+      }
+    },
+    "kind-of": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+      "dev": true
+    },
+    "levn": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+      "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+      "dev": true,
+      "requires": {
+        "prelude-ls": "^1.2.1",
+        "type-check": "~0.4.0"
+      }
+    },
+    "listenercount": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz",
+      "integrity": "sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=",
+      "dev": true
+    },
+    "loader-runner": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz",
+      "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==",
+      "dev": true
+    },
+    "loader-utils": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
+      "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
+      "dev": true,
+      "requires": {
+        "big.js": "^5.2.2",
+        "emojis-list": "^3.0.0",
+        "json5": "^1.0.1"
+      }
+    },
+    "locate-path": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+      "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+      "dev": true,
+      "requires": {
+        "p-locate": "^5.0.0"
+      }
+    },
+    "lodash.merge": {
+      "version": "4.6.2",
+      "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+      "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+      "dev": true
+    },
+    "lodash.truncate": {
+      "version": "4.4.2",
+      "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
+      "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=",
+      "dev": true
+    },
+    "log-symbols": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+      "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+      "dev": true,
+      "requires": {
+        "chalk": "^4.1.0",
+        "is-unicode-supported": "^0.1.0"
+      }
+    },
+    "lru-cache": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+      "dev": true,
+      "requires": {
+        "yallist": "^4.0.0"
+      }
+    },
+    "map-cache": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+      "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
+      "dev": true
+    },
+    "map-visit": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
+      "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
+      "dev": true,
+      "requires": {
+        "object-visit": "^1.0.0"
+      }
+    },
+    "memory-fs": {
+      "version": "0.5.0",
+      "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz",
+      "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==",
+      "dev": true,
+      "requires": {
+        "errno": "^0.1.3",
+        "readable-stream": "^2.0.1"
+      }
+    },
+    "merge-stream": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+      "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+      "dev": true
+    },
+    "merge2": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+      "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+      "dev": true
+    },
+    "micromatch": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
+      "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==",
+      "dev": true,
+      "requires": {
+        "braces": "^3.0.1",
+        "picomatch": "^2.2.3"
+      }
+    },
+    "mime-db": {
+      "version": "1.51.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz",
+      "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==",
+      "dev": true
+    },
+    "mime-types": {
+      "version": "2.1.34",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz",
+      "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==",
+      "dev": true,
+      "requires": {
+        "mime-db": "1.51.0"
+      }
+    },
+    "minimatch": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+      "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+      "dev": true,
+      "requires": {
+        "brace-expansion": "^1.1.7"
+      }
+    },
+    "minimist": {
+      "version": "1.2.5",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+      "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
+      "dev": true
+    },
+    "mixin-deep": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
+      "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
+      "dev": true,
+      "requires": {
+        "for-in": "^1.0.2",
+        "is-extendable": "^1.0.1"
+      },
+      "dependencies": {
+        "is-extendable": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+          "dev": true,
+          "requires": {
+            "is-plain-object": "^2.0.4"
+          }
+        }
+      }
+    },
+    "mkdirp": {
+      "version": "0.5.5",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
+      "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
+      "dev": true,
+      "requires": {
+        "minimist": "^1.2.5"
+      }
+    },
+    "mocha": {
+      "version": "9.2.0",
+      "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.0.tgz",
+      "integrity": "sha512-kNn7E8g2SzVcq0a77dkphPsDSN7P+iYkqE0ZsGCYWRsoiKjOt+NvXfaagik8vuDa6W5Zw3qxe8Jfpt5qKf+6/Q==",
+      "dev": true,
+      "requires": {
+        "@ungap/promise-all-settled": "1.1.2",
+        "ansi-colors": "4.1.1",
+        "browser-stdout": "1.3.1",
+        "chokidar": "3.5.3",
+        "debug": "4.3.3",
+        "diff": "5.0.0",
+        "escape-string-regexp": "4.0.0",
+        "find-up": "5.0.0",
+        "glob": "7.2.0",
+        "growl": "1.10.5",
+        "he": "1.2.0",
+        "js-yaml": "4.1.0",
+        "log-symbols": "4.1.0",
+        "minimatch": "3.0.4",
+        "ms": "2.1.3",
+        "nanoid": "3.2.0",
+        "serialize-javascript": "6.0.0",
+        "strip-json-comments": "3.1.1",
+        "supports-color": "8.1.1",
+        "which": "2.0.2",
+        "workerpool": "6.2.0",
+        "yargs": "16.2.0",
+        "yargs-parser": "20.2.4",
+        "yargs-unparser": "2.0.0"
+      },
+      "dependencies": {
+        "ms": {
+          "version": "2.1.3",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+          "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "8.1.1",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+          "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "ms": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+      "dev": true
+    },
+    "nanoid": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz",
+      "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==",
+      "dev": true
+    },
+    "nanomatch": {
+      "version": "1.2.13",
+      "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+      "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+      "dev": true,
+      "requires": {
+        "arr-diff": "^4.0.0",
+        "array-unique": "^0.3.2",
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "fragment-cache": "^0.2.1",
+        "is-windows": "^1.0.2",
+        "kind-of": "^6.0.2",
+        "object.pick": "^1.3.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      }
+    },
+    "natural-compare": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+      "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
+      "dev": true
+    },
+    "neo-async": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
+      "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
+      "dev": true
+    },
+    "nice-try": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
+      "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
+      "dev": true
+    },
+    "node-releases": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz",
+      "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==",
+      "dev": true
+    },
+    "normalize-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+      "dev": true
+    },
+    "object-copy": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+      "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
+      "dev": true,
+      "requires": {
+        "copy-descriptor": "^0.1.0",
+        "define-property": "^0.2.5",
+        "kind-of": "^3.0.3"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        },
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "object-visit": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
+      "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
+      "dev": true,
+      "requires": {
+        "isobject": "^3.0.0"
+      }
+    },
+    "object.pick": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+      "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
+      "dev": true,
+      "requires": {
+        "isobject": "^3.0.1"
+      }
+    },
+    "once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+      "dev": true,
+      "requires": {
+        "wrappy": "1"
+      }
+    },
+    "optionator": {
+      "version": "0.9.1",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
+      "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
+      "dev": true,
+      "requires": {
+        "deep-is": "^0.1.3",
+        "fast-levenshtein": "^2.0.6",
+        "levn": "^0.4.1",
+        "prelude-ls": "^1.2.1",
+        "type-check": "^0.4.0",
+        "word-wrap": "^1.2.3"
+      }
+    },
+    "p-limit": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+      "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+      "dev": true,
+      "requires": {
+        "yocto-queue": "^0.1.0"
+      }
+    },
+    "p-locate": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+      "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+      "dev": true,
+      "requires": {
+        "p-limit": "^3.0.2"
+      }
+    },
+    "p-try": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+      "dev": true
+    },
+    "parent-module": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+      "dev": true,
+      "requires": {
+        "callsites": "^3.0.0"
+      }
+    },
+    "parse-passwd": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
+      "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=",
+      "dev": true
+    },
+    "pascalcase": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+      "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
+      "dev": true
+    },
+    "path-exists": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+      "dev": true
+    },
+    "path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+      "dev": true
+    },
+    "path-key": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+      "dev": true
+    },
+    "path-type": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+      "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+      "dev": true
+    },
+    "picocolors": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
+      "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
+      "dev": true
+    },
+    "picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "dev": true
+    },
+    "pkg-dir": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+      "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+      "dev": true,
+      "requires": {
+        "find-up": "^4.0.0"
+      },
+      "dependencies": {
+        "find-up": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+          "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+          "dev": true,
+          "requires": {
+            "locate-path": "^5.0.0",
+            "path-exists": "^4.0.0"
+          }
+        },
+        "locate-path": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+          "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+          "dev": true,
+          "requires": {
+            "p-locate": "^4.1.0"
+          }
+        },
+        "p-limit": {
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+          "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+          "dev": true,
+          "requires": {
+            "p-try": "^2.0.0"
+          }
+        },
+        "p-locate": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+          "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+          "dev": true,
+          "requires": {
+            "p-limit": "^2.2.0"
+          }
+        }
+      }
+    },
+    "posix-character-classes": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
+      "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
+      "dev": true
+    },
+    "prelude-ls": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+      "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+      "dev": true
+    },
+    "process-nextick-args": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+      "dev": true
+    },
+    "progress": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+      "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+      "dev": true
+    },
+    "prr": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
+      "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=",
+      "dev": true
+    },
+    "punycode": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+      "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+      "dev": true
+    },
+    "queue-microtask": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+      "dev": true
+    },
+    "randombytes": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+      "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "^5.1.0"
+      }
+    },
+    "readable-stream": {
+      "version": "2.3.7",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+      "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+      "dev": true,
+      "requires": {
+        "core-util-is": "~1.0.0",
+        "inherits": "~2.0.3",
+        "isarray": "~1.0.0",
+        "process-nextick-args": "~2.0.0",
+        "safe-buffer": "~5.1.1",
+        "string_decoder": "~1.1.1",
+        "util-deprecate": "~1.0.1"
+      }
+    },
+    "readdirp": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+      "dev": true,
+      "requires": {
+        "picomatch": "^2.2.1"
+      }
+    },
+    "regex-not": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+      "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+      "dev": true,
+      "requires": {
+        "extend-shallow": "^3.0.2",
+        "safe-regex": "^1.1.0"
+      }
+    },
+    "regexpp": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
+      "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
+      "dev": true
+    },
+    "repeat-element": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz",
+      "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==",
+      "dev": true
+    },
+    "repeat-string": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+      "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
+      "dev": true
+    },
+    "require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
+      "dev": true
+    },
+    "require-from-string": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+      "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+      "dev": true
+    },
+    "require-main-filename": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+      "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
+      "dev": true
+    },
+    "resolve-cwd": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz",
+      "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=",
+      "dev": true,
+      "requires": {
+        "resolve-from": "^3.0.0"
+      },
+      "dependencies": {
+        "resolve-from": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
+          "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=",
+          "dev": true
+        }
+      }
+    },
+    "resolve-dir": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz",
+      "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=",
+      "dev": true,
+      "requires": {
+        "expand-tilde": "^2.0.0",
+        "global-modules": "^1.0.0"
+      },
+      "dependencies": {
+        "global-modules": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
+          "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
+          "dev": true,
+          "requires": {
+            "global-prefix": "^1.0.1",
+            "is-windows": "^1.0.1",
+            "resolve-dir": "^1.0.0"
+          }
+        }
+      }
+    },
+    "resolve-from": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+      "dev": true
+    },
+    "resolve-url": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+      "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
+      "dev": true
+    },
+    "ret": {
+      "version": "0.1.15",
+      "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+      "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
+      "dev": true
+    },
+    "reusify": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+      "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+      "dev": true
+    },
+    "rimraf": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+      "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+      "dev": true,
+      "requires": {
+        "glob": "^7.1.3"
+      }
+    },
+    "run-parallel": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+      "dev": true,
+      "requires": {
+        "queue-microtask": "^1.2.2"
+      }
+    },
+    "safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+      "dev": true
+    },
+    "safe-regex": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+      "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
+      "dev": true,
+      "requires": {
+        "ret": "~0.1.10"
+      }
+    },
+    "schema-utils": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
+      "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
+      "dev": true,
+      "requires": {
+        "@types/json-schema": "^7.0.8",
+        "ajv": "^6.12.5",
+        "ajv-keywords": "^3.5.2"
+      }
+    },
+    "semver": {
+      "version": "7.3.5",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
+      "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
+      "dev": true,
+      "requires": {
+        "lru-cache": "^6.0.0"
+      }
+    },
+    "serialize-javascript": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
+      "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
+      "dev": true,
+      "requires": {
+        "randombytes": "^2.1.0"
+      }
+    },
+    "set-blocking": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+      "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
+      "dev": true
+    },
+    "set-value": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
+      "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
+      "dev": true,
+      "requires": {
+        "extend-shallow": "^2.0.1",
+        "is-extendable": "^0.1.1",
+        "is-plain-object": "^2.0.3",
+        "split-string": "^3.0.1"
+      },
+      "dependencies": {
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        }
+      }
+    },
+    "setimmediate": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+      "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=",
+      "dev": true
+    },
+    "shebang-command": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+      "dev": true,
+      "requires": {
+        "shebang-regex": "^3.0.0"
+      }
+    },
+    "shebang-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+      "dev": true
+    },
+    "slash": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+      "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+      "dev": true
+    },
+    "slice-ansi": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
+      "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
+      "dev": true,
+      "requires": {
+        "ansi-styles": "^4.0.0",
+        "astral-regex": "^2.0.0",
+        "is-fullwidth-code-point": "^3.0.0"
+      }
+    },
+    "snapdragon": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+      "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
+      "dev": true,
+      "requires": {
+        "base": "^0.11.1",
+        "debug": "^2.2.0",
+        "define-property": "^0.2.5",
+        "extend-shallow": "^2.0.1",
+        "map-cache": "^0.2.2",
+        "source-map": "^0.5.6",
+        "source-map-resolve": "^0.5.0",
+        "use": "^3.1.0"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        },
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        }
+      }
+    },
+    "snapdragon-node": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+      "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
+      "dev": true,
+      "requires": {
+        "define-property": "^1.0.0",
+        "isobject": "^3.0.0",
+        "snapdragon-util": "^3.0.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^1.0.0"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        }
+      }
+    },
+    "snapdragon-util": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+      "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.2.0"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "source-list-map": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
+      "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==",
+      "dev": true
+    },
+    "source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true
+    },
+    "source-map-resolve": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
+      "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
+      "dev": true,
+      "requires": {
+        "atob": "^2.1.2",
+        "decode-uri-component": "^0.2.0",
+        "resolve-url": "^0.2.1",
+        "source-map-url": "^0.4.0",
+        "urix": "^0.1.0"
+      }
+    },
+    "source-map-support": {
+      "version": "0.5.21",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+      "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+      "dev": true,
+      "requires": {
+        "buffer-from": "^1.0.0",
+        "source-map": "^0.6.0"
+      }
+    },
+    "source-map-url": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz",
+      "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==",
+      "dev": true
+    },
+    "split-string": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+      "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
+      "dev": true,
+      "requires": {
+        "extend-shallow": "^3.0.0"
+      }
+    },
+    "sprintf-js": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+      "dev": true
+    },
+    "static-extend": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
+      "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
+      "dev": true,
+      "requires": {
+        "define-property": "^0.2.5",
+        "object-copy": "^0.1.0"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        }
+      }
+    },
+    "string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dev": true,
+      "requires": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      }
+    },
+    "string_decoder": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "~5.1.0"
+      }
+    },
+    "strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "requires": {
+        "ansi-regex": "^5.0.1"
+      }
+    },
+    "strip-json-comments": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+      "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+      "dev": true
+    },
+    "supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "requires": {
+        "has-flag": "^4.0.0"
+      }
+    },
+    "table": {
+      "version": "6.8.0",
+      "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz",
+      "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==",
+      "dev": true,
+      "requires": {
+        "ajv": "^8.0.1",
+        "lodash.truncate": "^4.4.2",
+        "slice-ansi": "^4.0.0",
+        "string-width": "^4.2.3",
+        "strip-ansi": "^6.0.1"
+      },
+      "dependencies": {
+        "ajv": {
+          "version": "8.9.0",
+          "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.9.0.tgz",
+          "integrity": "sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==",
+          "dev": true,
+          "requires": {
+            "fast-deep-equal": "^3.1.1",
+            "json-schema-traverse": "^1.0.0",
+            "require-from-string": "^2.0.2",
+            "uri-js": "^4.2.2"
+          }
+        },
+        "json-schema-traverse": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+          "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+          "dev": true
+        }
+      }
+    },
+    "tapable": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
+      "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
+      "dev": true
+    },
+    "terser": {
+      "version": "5.10.0",
+      "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz",
+      "integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==",
+      "dev": true,
+      "requires": {
+        "commander": "^2.20.0",
+        "source-map": "~0.7.2",
+        "source-map-support": "~0.5.20"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.7.3",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
+          "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
+          "dev": true
+        }
+      }
+    },
+    "terser-webpack-plugin": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.0.tgz",
+      "integrity": "sha512-LPIisi3Ol4chwAaPP8toUJ3L4qCM1G0wao7L3qNv57Drezxj6+VEyySpPw4B1HSO2Eg/hDY/MNF5XihCAoqnsQ==",
+      "dev": true,
+      "requires": {
+        "jest-worker": "^27.4.1",
+        "schema-utils": "^3.1.1",
+        "serialize-javascript": "^6.0.0",
+        "source-map": "^0.6.1",
+        "terser": "^5.7.2"
+      }
+    },
+    "text-table": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+      "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
+      "dev": true
+    },
+    "to-object-path": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+      "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.0.2"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "to-regex": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+      "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+      "dev": true,
+      "requires": {
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "regex-not": "^1.0.2",
+        "safe-regex": "^1.1.0"
+      }
+    },
+    "to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "dev": true,
+      "requires": {
+        "is-number": "^7.0.0"
+      }
+    },
+    "traverse": {
+      "version": "0.3.9",
+      "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz",
+      "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=",
+      "dev": true
+    },
+    "ts-loader": {
+      "version": "9.2.6",
+      "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.2.6.tgz",
+      "integrity": "sha512-QMTC4UFzHmu9wU2VHZEmWWE9cUajjfcdcws+Gh7FhiO+Dy0RnR1bNz0YCHqhI0yRowCE9arVnNxYHqELOy9Hjw==",
+      "dev": true,
+      "requires": {
+        "chalk": "^4.1.0",
+        "enhanced-resolve": "^5.0.0",
+        "micromatch": "^4.0.0",
+        "semver": "^7.3.4"
+      }
+    },
+    "tslib": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+      "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+      "dev": true
+    },
+    "tsutils": {
+      "version": "3.21.0",
+      "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
+      "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
+      "dev": true,
+      "requires": {
+        "tslib": "^1.8.1"
+      }
+    },
+    "type-check": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+      "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+      "dev": true,
+      "requires": {
+        "prelude-ls": "^1.2.1"
+      }
+    },
+    "type-fest": {
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+      "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+      "dev": true
+    },
+    "typescript": {
+      "version": "4.5.5",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz",
+      "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==",
+      "dev": true
+    },
+    "union-value": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
+      "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
+      "dev": true,
+      "requires": {
+        "arr-union": "^3.1.0",
+        "get-value": "^2.0.6",
+        "is-extendable": "^0.1.1",
+        "set-value": "^2.0.1"
+      }
+    },
+    "unset-value": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+      "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
+      "dev": true,
+      "requires": {
+        "has-value": "^0.3.1",
+        "isobject": "^3.0.0"
+      },
+      "dependencies": {
+        "has-value": {
+          "version": "0.3.1",
+          "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+          "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
+          "dev": true,
+          "requires": {
+            "get-value": "^2.0.3",
+            "has-values": "^0.1.4",
+            "isobject": "^2.0.0"
+          },
+          "dependencies": {
+            "isobject": {
+              "version": "2.1.0",
+              "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+              "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+              "dev": true,
+              "requires": {
+                "isarray": "1.0.0"
+              }
+            }
+          }
+        },
+        "has-values": {
+          "version": "0.1.4",
+          "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+          "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=",
+          "dev": true
+        }
+      }
+    },
+    "unzipper": {
+      "version": "0.10.11",
+      "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz",
+      "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==",
+      "dev": true,
+      "requires": {
+        "big-integer": "^1.6.17",
+        "binary": "~0.3.0",
+        "bluebird": "~3.4.1",
+        "buffer-indexof-polyfill": "~1.0.0",
+        "duplexer2": "~0.1.4",
+        "fstream": "^1.0.12",
+        "graceful-fs": "^4.2.2",
+        "listenercount": "~1.0.1",
+        "readable-stream": "~2.3.6",
+        "setimmediate": "~1.0.4"
+      }
+    },
+    "uri-js": {
+      "version": "4.4.1",
+      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+      "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+      "dev": true,
+      "requires": {
+        "punycode": "^2.1.0"
+      }
+    },
+    "urix": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+      "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
+      "dev": true
+    },
+    "use": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
+      "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
+      "dev": true
+    },
+    "util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+      "dev": true
+    },
+    "v8-compile-cache": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
+      "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
+      "dev": true
+    },
+    "watchpack": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz",
+      "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==",
+      "dev": true,
+      "requires": {
+        "glob-to-regexp": "^0.4.1",
+        "graceful-fs": "^4.1.2"
+      }
+    },
+    "webpack": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.3.2.tgz",
+      "integrity": "sha512-DXsfHoI6lQAR3KnQh7+FsRfs9fs+TEvzXCA35UbKv4kVuzslg7QCMAcpFRZNDMjdtm9N/PoO54XEzGN9TeacQg==",
+      "dev": true,
+      "requires": {
+        "@types/eslint-scope": "^3.7.0",
+        "@types/estree": "^0.0.45",
+        "@webassemblyjs/ast": "1.9.0",
+        "@webassemblyjs/helper-module-context": "1.9.0",
+        "@webassemblyjs/wasm-edit": "1.9.0",
+        "@webassemblyjs/wasm-parser": "1.9.0",
+        "acorn": "^8.0.4",
+        "browserslist": "^4.14.5",
+        "chrome-trace-event": "^1.0.2",
+        "enhanced-resolve": "^5.3.1",
+        "eslint-scope": "^5.1.1",
+        "events": "^3.2.0",
+        "glob-to-regexp": "^0.4.1",
+        "graceful-fs": "^4.2.4",
+        "json-parse-better-errors": "^1.0.2",
+        "loader-runner": "^4.1.0",
+        "mime-types": "^2.1.27",
+        "neo-async": "^2.6.2",
+        "pkg-dir": "^4.2.0",
+        "schema-utils": "^3.0.0",
+        "tapable": "^2.0.0",
+        "terser-webpack-plugin": "^5.0.3",
+        "watchpack": "^2.0.0",
+        "webpack-sources": "^2.1.1"
+      }
+    },
+    "webpack-cli": {
+      "version": "3.3.12",
+      "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.12.tgz",
+      "integrity": "sha512-NVWBaz9k839ZH/sinurM+HcDvJOTXwSjYp1ku+5XKeOC03z8v5QitnK/x+lAxGXFyhdayoIf/GOpv85z3/xPag==",
+      "dev": true,
+      "requires": {
+        "chalk": "^2.4.2",
+        "cross-spawn": "^6.0.5",
+        "enhanced-resolve": "^4.1.1",
+        "findup-sync": "^3.0.0",
+        "global-modules": "^2.0.0",
+        "import-local": "^2.0.0",
+        "interpret": "^1.4.0",
+        "loader-utils": "^1.4.0",
+        "supports-color": "^6.1.0",
+        "v8-compile-cache": "^2.1.1",
+        "yargs": "^13.3.2"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+          "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+          "dev": true
+        },
+        "ansi-styles": {
+          "version": "3.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^1.9.0"
+          }
+        },
+        "camelcase": {
+          "version": "5.3.1",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+          "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+          "dev": true
+        },
+        "chalk": {
+          "version": "2.4.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^3.2.1",
+            "escape-string-regexp": "^1.0.5",
+            "supports-color": "^5.3.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "5.5.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+              "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+              "dev": true,
+              "requires": {
+                "has-flag": "^3.0.0"
+              }
+            }
+          }
+        },
+        "cliui": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
+          "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
+          "dev": true,
+          "requires": {
+            "string-width": "^3.1.0",
+            "strip-ansi": "^5.2.0",
+            "wrap-ansi": "^5.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "1.9.3",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+          "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+          "dev": true,
+          "requires": {
+            "color-name": "1.1.3"
+          }
+        },
+        "color-name": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "dev": true
+        },
+        "cross-spawn": {
+          "version": "6.0.5",
+          "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+          "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+          "dev": true,
+          "requires": {
+            "nice-try": "^1.0.4",
+            "path-key": "^2.0.1",
+            "semver": "^5.5.0",
+            "shebang-command": "^1.2.0",
+            "which": "^1.2.9"
+          }
+        },
+        "decamelize": {
+          "version": "1.2.0",
+          "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+          "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+          "dev": true
+        },
+        "emoji-regex": {
+          "version": "7.0.3",
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
+          "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
+          "dev": true
+        },
+        "enhanced-resolve": {
+          "version": "4.5.0",
+          "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz",
+          "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==",
+          "dev": true,
+          "requires": {
+            "graceful-fs": "^4.1.2",
+            "memory-fs": "^0.5.0",
+            "tapable": "^1.0.0"
+          }
+        },
+        "escape-string-regexp": {
+          "version": "1.0.5",
+          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+          "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+          "dev": true
+        },
+        "find-up": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+          "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+          "dev": true,
+          "requires": {
+            "locate-path": "^3.0.0"
+          }
+        },
+        "has-flag": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "dev": true
+        },
+        "is-fullwidth-code-point": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+          "dev": true
+        },
+        "locate-path": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+          "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+          "dev": true,
+          "requires": {
+            "p-locate": "^3.0.0",
+            "path-exists": "^3.0.0"
+          }
+        },
+        "p-limit": {
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+          "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+          "dev": true,
+          "requires": {
+            "p-try": "^2.0.0"
+          }
+        },
+        "p-locate": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+          "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+          "dev": true,
+          "requires": {
+            "p-limit": "^2.0.0"
+          }
+        },
+        "path-exists": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+          "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+          "dev": true
+        },
+        "path-key": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+          "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
+          "dev": true
+        },
+        "semver": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+          "dev": true
+        },
+        "shebang-command": {
+          "version": "1.2.0",
+          "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+          "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+          "dev": true,
+          "requires": {
+            "shebang-regex": "^1.0.0"
+          }
+        },
+        "shebang-regex": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+          "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
+          "dev": true
+        },
+        "string-width": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+          "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+          "dev": true,
+          "requires": {
+            "emoji-regex": "^7.0.1",
+            "is-fullwidth-code-point": "^2.0.0",
+            "strip-ansi": "^5.1.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+          "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^4.1.0"
+          }
+        },
+        "supports-color": {
+          "version": "6.1.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+          "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        },
+        "tapable": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz",
+          "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==",
+          "dev": true
+        },
+        "which": {
+          "version": "1.3.1",
+          "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+          "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+          "dev": true,
+          "requires": {
+            "isexe": "^2.0.0"
+          }
+        },
+        "wrap-ansi": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
+          "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^3.2.0",
+            "string-width": "^3.0.0",
+            "strip-ansi": "^5.0.0"
+          }
+        },
+        "y18n": {
+          "version": "4.0.3",
+          "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
+          "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
+          "dev": true
+        },
+        "yargs": {
+          "version": "13.3.2",
+          "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
+          "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
+          "dev": true,
+          "requires": {
+            "cliui": "^5.0.0",
+            "find-up": "^3.0.0",
+            "get-caller-file": "^2.0.1",
+            "require-directory": "^2.1.1",
+            "require-main-filename": "^2.0.0",
+            "set-blocking": "^2.0.0",
+            "string-width": "^3.0.0",
+            "which-module": "^2.0.0",
+            "y18n": "^4.0.0",
+            "yargs-parser": "^13.1.2"
+          }
+        },
+        "yargs-parser": {
+          "version": "13.1.2",
+          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
+          "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
+          "dev": true,
+          "requires": {
+            "camelcase": "^5.0.0",
+            "decamelize": "^1.2.0"
+          }
+        }
+      }
+    },
+    "webpack-sources": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.3.1.tgz",
+      "integrity": "sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA==",
+      "dev": true,
+      "requires": {
+        "source-list-map": "^2.0.1",
+        "source-map": "^0.6.1"
+      }
+    },
+    "which": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+      "dev": true,
+      "requires": {
+        "isexe": "^2.0.0"
+      }
+    },
+    "which-module": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+      "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
+      "dev": true
+    },
+    "word-wrap": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+      "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+      "dev": true
+    },
+    "workerpool": {
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz",
+      "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==",
+      "dev": true
+    },
+    "wrap-ansi": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+      "dev": true,
+      "requires": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      }
+    },
+    "wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+      "dev": true
+    },
+    "y18n": {
+      "version": "5.0.8",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+      "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+      "dev": true
+    },
+    "yallist": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+      "dev": true
+    },
+    "yargs": {
+      "version": "16.2.0",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
+      "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
+      "dev": true,
+      "requires": {
+        "cliui": "^7.0.2",
+        "escalade": "^3.1.1",
+        "get-caller-file": "^2.0.5",
+        "require-directory": "^2.1.1",
+        "string-width": "^4.2.0",
+        "y18n": "^5.0.5",
+        "yargs-parser": "^20.2.2"
+      }
+    },
+    "yargs-parser": {
+      "version": "20.2.4",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
+      "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
+      "dev": true
+    },
+    "yargs-unparser": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
+      "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
+      "dev": true,
+      "requires": {
+        "camelcase": "^6.0.0",
+        "decamelize": "^4.0.0",
+        "flat": "^5.0.2",
+        "is-plain-obj": "^2.1.0"
+      }
+    },
+    "yocto-queue": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+      "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+      "dev": true
+    }
+  }
+}
diff --git a/ide_tooling/cros-ide/package.json b/ide_tooling/cros-ide/package.json
new file mode 100644
index 0000000..3e7a913
--- /dev/null
+++ b/ide_tooling/cros-ide/package.json
@@ -0,0 +1,243 @@
+{
+  "name": "cros-ide",
+  "displayName": "cros-ide",
+  "description": "Connect to Chrome OS DUTs over VNC",
+  "version": "0.0.4",
+  "publisher": "cros-velocity",
+  "repository": "https://chromium.googlesource.com/chromiumos/chromite/+/HEAD/ide_tooling",
+  "engines": {
+    "vscode": "^1.63.1"
+  },
+  "categories": [
+    "Other"
+  ],
+  "activationEvents": [
+    "onCommand:cros-ide.addHost",
+    "onCommand:cros-ide.deleteHost",
+    "onCommand:cros-ide.connectToHostForScreen",
+    "onCommand:cros-ide.connectToHostForShell",
+    "onCommand:cros-ide.refreshCrosfleet",
+    "onCommand:cros-ide.addFleetHost",
+    "onCommand:cros-ide.codeSearchOpenCurrentFile",
+    "onCommand:cros-ide.codeSearchSearchForSelection",
+    "onCommand:cros-ide.crosWorkonStart",
+    "onCommand:cros-ide.crosWorkonStop",
+    "onView:static-devices",
+    "onView:fleet-devices",
+    "onView:boards-packages",
+    "onLanguage:cpp",
+    "onLanguage:gn",
+    "onLanguage:python",
+    "onLanguage:shellscript"
+  ],
+  "main": "./dist/extension.js",
+  "contributes": {
+    "commands": [
+      {
+        "command": "cros-ide.connectToHostForScreen",
+        "title": "CrOS: Connect to Host (VNC)",
+        "icon": "$(window)"
+      },
+      {
+        "command": "cros-ide.connectToHostForShell",
+        "title": "CrOS: Connect to Host (Shell)",
+        "icon": "$(terminal)"
+      },
+      {
+        "command": "cros-ide.addHost",
+        "title": "CrOS: Add New Host",
+        "icon": "$(add)"
+      },
+      {
+        "command": "cros-ide.deleteHost",
+        "title": "CrOS: Delete Host",
+        "icon": "$(remove)"
+      },
+      {
+        "command": "cros-ide.refreshCrosfleet",
+        "title": "CrOS: Refresh crosfleet devices",
+        "icon": "$(refresh)"
+      },
+      {
+        "command": "cros-ide.addFleetHost",
+        "title": "CrOS: Add crosfleet Host",
+        "icon": "$(add)"
+      },
+      {
+        "command": "cros-ide.refreshBoardsPackages",
+        "title": "CrOS: Refresh Boards and Packages",
+        "icon": "$(refresh)"
+      },
+      {
+        "command": "cros-ide.codeSearchOpenCurrentFile",
+        "title": "Open in Code Search"
+      },
+      {
+        "command": "cros-ide.codeSearchSearchForSelection",
+        "title": "Search for selection in Code Search"
+      },
+      {
+        "command": "cros-ide.crosWorkonStart",
+        "title": "CrOS: Start Working on a Package"
+      },
+      {
+        "command": "cros-ide.crosWorkonStop",
+        "title": "CrOS: Stop Working on a Package"
+      },
+      {
+        "command": "cros-ide.selectBoard",
+        "title": "CrOS: Select target board"
+      }
+    ],
+    "viewsContainers": {
+      "activitybar": [
+        {
+          "id": "cros-devices",
+          "title": "CrOS Remote Testing",
+          "icon": "media/cros-device.svg"
+        }
+      ]
+    },
+    "views": {
+      "cros-devices": [
+        {
+          "id": "static-devices",
+          "name": "my devices"
+        },
+        {
+          "id": "fleet-devices",
+          "name": "crosfleet devices"
+        },
+        {
+          "id": "boards-packages",
+          "name": "Boards and Packages"
+        }
+      ]
+    },
+    "menus": {
+      "editor/context": [
+        {
+          "command": "cros-ide.codeSearchOpenCurrentFile"
+        },
+        {
+          "command": "cros-ide.codeSearchSearchForSelection"
+        }
+      ],
+      "view/title": [
+        {
+          "command": "cros-ide.addHost",
+          "when": "view == static-devices",
+          "group": "navigation"
+        },
+        {
+          "command": "cros-ide.addFleetHost",
+          "when": "view == fleet-devices",
+          "group": "navigation"
+        },
+        {
+          "command": "cros-ide.refreshCrosfleet",
+          "when": "view == fleet-devices",
+          "group": "navigation"
+        },
+        {
+          "command": "cros-ide.refreshBoardsPackages",
+          "when": "view == boards-packages",
+          "group": "navigation"
+        }
+      ],
+      "view/item/context": [
+        {
+          "command": "cros-ide.connectToHostForScreen",
+          "when": "view == static-devices || view == fleet-devices",
+          "group": "inline@1"
+        },
+        {
+          "command": "cros-ide.connectToHostForShell",
+          "when": "view == static-devices || view == fleet-devices",
+          "group": "inline@2"
+        },
+        {
+          "command": "cros-ide.deleteHost",
+          "when": "view == static-devices || view == fleet-devices",
+          "group": "inline@3"
+        }
+      ]
+    },
+    "viewsWelcome": [
+      {
+        "view": "static-devices",
+        "contents": "No host added yet.\n[Add New Host](command:cros-ide.addHost)"
+      }
+    ],
+    "configuration": {
+      "title": "CrOS IDE",
+      "properties": {
+        "cros-ide.board": {
+          "type": "string",
+          "description": "The board to use on commands such as emerge"
+        },
+        "cros-ide.codeSearch": {
+          "type": "string",
+          "enum": [
+            "public",
+            "internal",
+            "gitiles"
+          ],
+          "description": "Code Search instance to open files in",
+          "default": "public"
+        },
+        "cros-ide.features.testCoverage": {
+          "type": "boolean",
+          "description": "Enable Test Coverage",
+          "default": false
+        },
+        "cros-ide.hosts": {
+          "type": "array",
+          "scope": "machine-overridable",
+          "description": "List of devices under testing",
+          "items": {
+            "type": "string"
+          }
+        }
+      }
+    },
+    "languages": [
+      {
+        "id": "shellscript",
+        "extensions": [
+          ".eclass"
+        ],
+        "aliases": [
+          "Eclass"
+        ]
+      }
+    ]
+  },
+  "scripts": {
+    "vscode:prepublish": "npm run package",
+    "compile": "webpack",
+    "package": "webpack --mode production --devtool hidden-source-map",
+    "compile-tests": "tsc -p . --outDir out",
+    "lint": "eslint src --ext ts",
+    "test": "npm run compile-tests && npm run compile && npm run lint && xvfb-run -a node ./out/test/runTest.js",
+    "unit-test": "npm run compile-tests && node ./node_modules/mocha/bin/_mocha -u tdd --timeout 5000 --colors ./out/test/unit",
+    "publish": "./install.sh --upload"
+  },
+  "devDependencies": {
+    "@types/glob": "^7.1.4",
+    "@types/mocha": "^9.0.0",
+    "@types/node": "^12.16.1",
+    "@types/vscode": "^1.63.1",
+    "@typescript-eslint/eslint-plugin": "^5.1.0",
+    "@typescript-eslint/parser": "^5.1.0",
+    "@vscode/test-electron": "^1.6.2",
+    "eslint": "^7",
+    "eslint-config-google": "^0.14.0",
+    "glob": "^7.1.7",
+    "mocha": "^9.1.3",
+    "ts-loader": "~9.2.6",
+    "typescript": "^4.5.5",
+    "webpack": "~5.3.2",
+    "webpack-cli": "~3.3.11"
+  }
+}
diff --git a/ide_tooling/cros-ide/preupload_hook.sh b/ide_tooling/cros-ide/preupload_hook.sh
new file mode 100755
index 0000000..5d84950
--- /dev/null
+++ b/ide_tooling/cros-ide/preupload_hook.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+# Copyright 2022 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Run tests to ensure the extension works.
+set -e
+
+# Ignore changes outside of ide_tooling/cros_ide.
+if ! [[ "$*" =~ /chromite/ide_tooling/cros-ide/ ]]; then
+  exit 0
+fi
+
+cd "$(dirname "$0")" || exit 1
+
+npx ts-node ./src/tools/preupload_hook.ts
diff --git a/ide_tooling/cros-ide/resources/testing_rsa b/ide_tooling/cros-ide/resources/testing_rsa
new file mode 100644
index 0000000..c841b72
--- /dev/null
+++ b/ide_tooling/cros-ide/resources/testing_rsa
@@ -0,0 +1,28 @@
+# Externally Available Public Testing Key from: https://chromium.googlesource.com/chromiumos/chromite/+/main/ssh_keys/testing_rsa
+-----BEGIN RSA PRIVATE KEY-----
+MIIEoAIBAAKCAQEAvsNpFdK5lb0GfKx+FgsrsM/2+aZVFYXHMPdvGtTz63ciRhq0
+Jnw7nln1SOcHraSz3/imECBg8NHIKV6rA+B9zbf7pZXEv20x5Ul0vrcPqYWC44PT
+tgsgvi8s0KZUZN93YlcjZ+Q7BjQ/tuwGSaLWLqJ7hnHALMJ3dbEM9fKBHQBCrG5H
+OaWD2gtXj7jp04M/WUnDDdemq/KMg6E9jcrJOiQ39IuTpas4hLQzVkKAKSrpl6MY
+2etHyoNarlWhcOwitArEDwf3WgnctwKstI/MTKB5BTpO2WXUNUv4kXzA+g8/l1al
+jIG13vtd9A/IV3KFVx/sLkkjuZ7z2rQXyNKuJwIBIwKCAQA79EWZJPh/hI0CnJyn
+16AEXp4T8nKDG2p9GpCiCGnq6u2Dvz/u1pZk97N9T+x4Zva0GvJc1vnlST7objW/
+Y8/ET8QeGSCT7x5PYDqiVspoemr3DCyYTKPkADKn+cLAngDzBXGHDTcfNP4U6xfr
+Qc5JK8BsFR8kApqSs/zCU4eqBtp2FVvPbgUOv3uUrFnjEuGs9rb1QZ0K6o08L4Cq
+N+e2nTysjp78blakZfqlurqTY6iJb0ImU2W3T8sV6w5GP1NT7eicXLO3WdIRB15a
+evogPeqtMo8GcO62wU/D4UCvq4GNEjvYOvFmPzXHvhTxsiWv5KEACtleBIEYmWHA
+POwrAoGBAOKgNRgxHL7r4bOmpLQcYK7xgA49OpikmrebXCQnZ/kZ3QsLVv1QdNMH
+Rx/ex7721g8R0oWslM14otZSMITCDCMWTYVBNM1bqYnUeEu5HagFwxjQ2tLuSs8E
+SBzEr96JLfhwuBhDH10sQqn+OQG1yj5acs4Pt3L4wlYwMx0vs1BxAoGBANd9Owro
+5ONiJXfKNaNY/cJYuLR+bzGeyp8oxToxgmM4UuA4hhDU7peg4sdoKJ4XjB9cKMCz
+ZGU5KHKKxNf95/Z7aywiIJEUE/xPRGNP6tngRunevp2QyvZf4pgvACvk1tl9B3HH
+7J5tY/GRkT4sQuZYpx3YnbdP5Y6Kx33BF7QXAoGAVCzghVQR/cVT1QNhvz29gs66
+iPIrtQnwUtNOHA6i9h+MnbPBOYRIpidGTaqEtKTTKisw79JjJ78X6TR4a9ML0oSg
+c1K71z9NmZgPbJU25qMN80ZCph3+h2f9hwc6AjLz0U5wQ4alP909VRVIX7iM8paf
+q59wBiHhyD3J16QAxhsCgYBu0rCmhmcV2rQu+kd4lCq7uJmBZZhFZ5tny9MlPgiK
+zIJkr1rkFbyIfqCDzyrU9irOTKc+iCUA25Ek9ujkHC4m/aTU3lnkNjYp/OFXpXF3
+XWZMY+0Ak5uUpldG85mwLIvATu3ivpbyZCTFYM5afSm4StmaUiU5tA+oZKEcGily
+jwKBgBdFLg+kTm877lcybQ04G1kIRMf5vAXcConzBt8ry9J+2iX1ddlu2K2vMroD
+1cP/U/EmvoCXSOGuetaI4UNQwE/rGCtkpvNj5y4twVLh5QufSOl49V0Ut0mwjPXw
+HfN/2MoO07vQrjgsFylvrw9A79xItABaqKndlmqlwMZWc9Ne
+-----END RSA PRIVATE KEY-----
diff --git a/ide_tooling/cros-ide/src/boards_packages.ts b/ide_tooling/cros-ide/src/boards_packages.ts
new file mode 100644
index 0000000..815a959
--- /dev/null
+++ b/ide_tooling/cros-ide/src/boards_packages.ts
@@ -0,0 +1,67 @@
+// Copyright 2022 The Chromium OS 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 * as vscode from 'vscode';
+import * as cros from './common/cros';
+
+export function activate() {
+  const boardPackageProvider = new BoardPackageProvider();
+
+  vscode.window.registerTreeDataProvider(
+      'boards-packages',
+      boardPackageProvider,
+  );
+
+  vscode.commands.registerCommand(
+      'cros-ide.refreshBoardsPackages',
+      () => boardPackageProvider.refresh(),
+  );
+}
+
+/**
+ * Provides two-level tree. The top level are boards set up with
+ * `setup_board --board=${BOARD}`, under each board we show packages
+ * that are `cros_work start`-ed.
+ *
+ * Everything is read-only and does not refresh after the IDE is loaded.
+ */
+class BoardPackageProvider implements vscode.TreeDataProvider<ChrootItem> {
+  private onDidChangeTreeDataEmitter =
+    new vscode.EventEmitter<ChrootItem | undefined | null | void>();
+  readonly onDidChangeTreeData = this.onDidChangeTreeDataEmitter.event;
+
+  async getChildren(element?: ChrootItem): Promise<ChrootItem[]> {
+    if (element === undefined) {
+      return (await cros.getSetupBoards()).map(x => new Board(x));
+    }
+    if (element && element instanceof Board) {
+      return (await cros.getWorkedOnPackages(element.name)).map(x =>
+        new Package(x));
+    }
+    return Promise.resolve([]);
+  }
+
+  getTreeItem(element: ChrootItem): vscode.TreeItem {
+    return element;
+  }
+
+  refresh(): void {
+    this.onDidChangeTreeDataEmitter.fire();
+  }
+}
+
+class ChrootItem extends vscode.TreeItem {
+}
+
+class Board extends ChrootItem {
+  constructor(readonly name: string) {
+    super(name, vscode.TreeItemCollapsibleState.Collapsed);
+  }
+}
+
+class Package extends ChrootItem {
+  constructor(readonly name: string) {
+    super(name, vscode.TreeItemCollapsibleState.None);
+  }
+}
diff --git a/ide_tooling/cros-ide/src/codesearch.ts b/ide_tooling/cros-ide/src/codesearch.ts
new file mode 100644
index 0000000..4d486b8
--- /dev/null
+++ b/ide_tooling/cros-ide/src/codesearch.ts
@@ -0,0 +1,63 @@
+// Copyright 2022 The Chromium OS 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 * as childProcess from 'child_process';
+import * as ideUtilities from './ide_utilities';
+import * as vscode from 'vscode';
+
+export function activate(context: vscode.ExtensionContext) {
+  const openFileCmd =
+    vscode.commands.registerTextEditorCommand(
+        'cros-ide.codeSearchOpenCurrentFile',
+        openCurrentFile);
+
+  const searchSelectionCmd = vscode.commands.registerTextEditorCommand(
+      'cros-ide.codeSearchSearchForSelection',
+      searchSelection);
+
+  context.subscriptions.push(openFileCmd, searchSelectionCmd);
+}
+
+const generateCsPath = '~/chromiumos/chromite/contrib/generate_cs_path';
+
+function openCurrentFile(textEditor: vscode.TextEditor) {
+  const fullpath = textEditor.document.fileName;
+
+  // Which CodeSearch to use, options are public, internal, or gitiles.
+  const csInstance = ideUtilities.getConfigRoot().get<string>('codeSearch');
+
+  const line = textEditor.selection.active.line + 1;
+
+  // generate_cs_path is a symlink that uses a wrapper to call a Python script,
+  // so it seems we need exec(), which spawn a shell.
+  childProcess.exec(
+      `${generateCsPath} --show "--${csInstance}" --line=${line} "${fullpath}"`,
+      (error, stdout, stderr) => {
+        if (error) {
+          console.log(stderr);
+          return;
+        }
+        // trimEnd() to get rid of the newline.
+        vscode.env.openExternal(vscode.Uri.parse(stdout.trimEnd()));
+      },
+  );
+}
+
+// TODO: Figure out if the search should be limited to the current repo.
+function searchSelection(textEditor: vscode.TextEditor) {
+  if (textEditor.selection.isEmpty) {
+    return;
+  }
+
+  // If the setting is gitiles, we use public CodeSearch
+  const csInstance = ideUtilities.getConfigRoot().get<string>('codesearch');
+  const csBase =
+    csInstance == 'internal' ?
+        'https://source.corp.google.com/' : 'https://source.chromium.org/';
+
+  const selectedText = textEditor.document.getText(textEditor.selection);
+  const uri =
+      vscode.Uri.parse(csBase)
+          .with({path: '/search', query: `q=${selectedText}`});
+  vscode.env.openExternal(uri);
+}
diff --git a/ide_tooling/cros-ide/src/common/common_util.ts b/ide_tooling/cros-ide/src/common/common_util.ts
new file mode 100644
index 0000000..3d8d6a0
--- /dev/null
+++ b/ide_tooling/cros-ide/src/common/common_util.ts
@@ -0,0 +1,159 @@
+// Copyright 2022 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * Common utilities between extension code and tools such as installtion
+ * script. This file should not depend on 'vscode'.
+ */
+
+import * as childProcess from 'child_process';
+import * as fs from 'fs';
+import * as os from 'os';
+
+export function isInsideChroot(): boolean {
+  return fs.existsSync('/etc/cros_chroot_version');
+}
+
+class Task<T> {
+  constructor(readonly job: () => Promise<T>,
+    readonly resolve: (x: T | null) => void,
+    readonly reject: (reason?: any) => void) {
+  }
+  cancel() {
+    this.resolve(null);
+  }
+  async run() {
+    try {
+      this.resolve(await this.job());
+    } catch (e) {
+      this.reject(e);
+    }
+  }
+}
+
+/**
+ * JobManager manages jobs and ensures that only one job is run at a time. If
+ * multiple jobs are in queue waiting for a running job, the manager cancels all
+ * but the last job.
+ */
+export class JobManager<T> {
+  // Queued tasks.
+  private tasks: Task<T>[] = [];
+  // True iff the a task is running.
+  private running = false;
+
+  constructor() { }
+
+  /**
+   * Pushes a job and returns a promise that is fulfilled after the job is
+   * cancalled or completed. If the job is cancelled, the returned promise is
+   * resolved with null.
+   */
+  offer(job: () => Promise<T>): Promise<T | null> {
+    return new Promise((resolve, reject) => {
+      this.tasks.push(new Task(job, resolve, reject));
+      this.handle();
+    });
+  }
+
+  private async handle(): Promise<void> {
+    while (this.tasks.length > 1) {
+      this.tasks.shift()!.cancel(); // cancel old tasks
+    }
+    if (this.running) {
+      return;
+    }
+    const task = this.tasks.pop();
+    if (!task) {
+      return;
+    }
+
+    this.running = true;
+    await task.run();
+    this.running = false;
+    await this.handle(); // handle possible new task
+  }
+}
+
+/**
+ * Executes command with optionally logging its output. The promise will be
+ * resolved with stdout of the command. It's guaranteed that data passed to log
+ * ends with a newline.
+ * @param log Optional logging function.
+ * @param opt Optional parameters. Set opt.logStdout to true to log stdout in
+ * addition to stderr.
+ */
+export function exec(name: string, args: string[],
+    log?: (line: string) => void,
+    opt?: { logStdout?: boolean }): Promise<string> {
+  return execPtr(name, args, log, opt);
+}
+
+let execPtr = realExec;
+
+export function setExecForTesting(fakeExec: typeof exec): () => void {
+  const original = execPtr;
+  execPtr = fakeExec;
+  return () => {
+    execPtr = original;
+  };
+}
+
+function realExec(name: string, args: string[],
+    log?: (line: string) => void,
+    opt?: { logStdout?: boolean }): Promise<string> {
+  return new Promise((resolve, reject) => {
+    const command = childProcess.spawn(name, args);
+
+    let remainingStdout = '';
+    let remainingStderr = '';
+    let response = '';
+    command.stdout.on('data', data => {
+      if (log && opt && opt.logStdout) {
+        remainingStdout += data;
+        const i = remainingStdout.lastIndexOf('\n');
+        log(remainingStdout.substring(0, i + 1));
+        remainingStdout = remainingStdout.substring(i + 1);
+      }
+      response += data;
+    });
+    if (log) {
+      command.stderr.on('data', data => {
+        remainingStderr += data;
+        const i = remainingStderr.lastIndexOf('\n');
+        log(remainingStderr.substring(0, i + 1));
+        remainingStderr = remainingStderr.substring(i + 1);
+      });
+    }
+    command.on('close', (code) => {
+      if (log && opt && opt.logStdout && remainingStdout) {
+        log(remainingStdout + '\n');
+      }
+      if (log && remainingStderr) {
+        log(remainingStderr + '\n');
+      }
+      if (code !== 0) {
+        reject(new Error(`Exit code: ${code}`));
+      }
+      resolve(response);
+    });
+    // 'error' happens when the command is not available
+    command.on('error', (err) => {
+      reject(err);
+    });
+  });
+}
+
+export async function withTempDir(
+    f: (tempDir: string) => Promise<void>): Promise<void> {
+  let td: string | undefined;
+  try {
+    td = await fs.promises.mkdtemp(os.tmpdir() + '/');
+    await f(td);
+  } finally {
+    if (td) {
+      await fs.promises.rmdir(td, {recursive: true});
+    }
+  }
+}
diff --git a/ide_tooling/cros-ide/src/common/cros.ts b/ide_tooling/cros-ide/src/common/cros.ts
new file mode 100644
index 0000000..14988d2
--- /dev/null
+++ b/ide_tooling/cros-ide/src/common/cros.ts
@@ -0,0 +1,39 @@
+// Copyright 2022 The Chromium OS 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 * as fs from 'fs';
+import * as path from 'path';
+import * as commonUtil from './common_util';
+
+/**
+ * @returns Boards that have been set up, ordered by access time (newest to
+ * oldest).
+ */
+export async function getSetupBoards(rootDir: string = '/'): Promise<string[]> {
+  const build = path.join(rootDir, 'build');
+  const dirs = await fs.promises.readdir(build);
+  const dirStat: Array<[string, fs.Stats]> = [];
+  for (const dir of dirs) {
+    if (dir === 'bin') {
+      continue;
+    }
+    dirStat.push([dir, await fs.promises.stat(path.join(build, dir))]);
+  }
+  dirStat.sort(([, a], [, b]) => {
+    if (a.atimeMs === b.atimeMs) {
+      return 0;
+    }
+    return a.atimeMs < b.atimeMs ? 1 : -1;
+  });
+  return dirStat.map(([x]) => x);
+}
+
+/**
+ * @returns Packages that are worked on.
+ */
+export async function getWorkedOnPackages(board: string): Promise<string[]> {
+  const stdout = await commonUtil.exec(
+      'cros_workon', ['--board', board, 'list']);
+  return stdout.split('\n').filter(x => x.trim() !== '');
+}
diff --git a/ide_tooling/cros-ide/src/coverage.ts b/ide_tooling/cros-ide/src/coverage.ts
new file mode 100644
index 0000000..d03fa10
--- /dev/null
+++ b/ide_tooling/cros-ide/src/coverage.ts
@@ -0,0 +1,47 @@
+// Copyright 2022 The Chromium OS 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 * as vscode from 'vscode';
+
+export function activate(context: vscode.ExtensionContext) {
+  // Highlight colors were copied from Code Search.
+  const coveredDecoration = vscode.window.createTextEditorDecorationType({
+    light: {backgroundColor: '#e5ffe5'},
+    dark: {backgroundColor: 'rgba(13,101,45,0.5)'},
+    isWholeLine: true,
+  });
+  const uncoveredDecoration = vscode.window.createTextEditorDecorationType({
+    light: {backgroundColor: '#ffe5e5'},
+    dark: {backgroundColor: 'rgba(168,19,20,0.5)'},
+    isWholeLine: true,
+  });
+
+  let activeEditor = vscode.window.activeTextEditor;
+
+  function updateDecorations() {
+    if (!activeEditor) {
+      return;
+    }
+
+    // We hard-code two ranges to demonstrate the UI.
+
+    activeEditor.setDecorations(
+        coveredDecoration,
+        [{
+          range: new vscode.Range(10, 0, 15, Number.MAX_VALUE),
+        }]);
+
+    activeEditor.setDecorations(
+        uncoveredDecoration,
+        [{
+          range: new vscode.Range(18, 0, 25, Number.MAX_VALUE),
+        }]);
+  }
+
+  updateDecorations();
+
+  vscode.window.onDidChangeActiveTextEditor(editor => {
+    activeEditor = editor;
+    updateDecorations();
+  });
+}
diff --git a/ide_tooling/cros-ide/src/cpp_code_completion.ts b/ide_tooling/cros-ide/src/cpp_code_completion.ts
new file mode 100644
index 0000000..54d1058
--- /dev/null
+++ b/ide_tooling/cros-ide/src/cpp_code_completion.ts
@@ -0,0 +1,146 @@
+// Copyright 2022 The Chromium OS 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 * as fs from 'fs';
+import * as path from 'path';
+import * as vscode from 'vscode';
+
+import * as commonUtil from './common/common_util';
+import * as ideUtilities from './ide_utilities';
+
+export function activate(context: vscode.ExtensionContext) {
+  const manager = new commonUtil.JobManager<void>();
+
+  context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(
+      editor => {
+        if (editor?.document.languageId === 'cpp') {
+          generateCompilationDatabase(manager, editor.document);
+        }
+      },
+  ));
+
+  // Update compilation database when a GN file is updated.
+  context.subscriptions.push(vscode.workspace.onDidSaveTextDocument(
+      document => {
+        if (document.fileName.match(/\.gni?$/)) {
+          generateCompilationDatabase(manager, document);
+        }
+      },
+  ));
+
+  const document = vscode.window.activeTextEditor?.document;
+  if (document) {
+    generateCompilationDatabase(manager, document);
+  }
+}
+
+export interface PackageInfo {
+  sourceDir: string, // directory containing source code relative to chromiumos/
+  pkg: string, // package name
+}
+
+const MNT_HOST_SOURCE = '/mnt/host/source'; // realpath of ~/chromiumos
+
+// Generate compilation database for clangd.
+// TODO(oka): Add unit test.
+async function generateCompilationDatabase(
+    manager: commonUtil.JobManager<void>,
+    document: vscode.TextDocument,
+) {
+  const packageInfo = await getPackage(document.fileName);
+  if (!packageInfo) {
+    return;
+  }
+  const {sourceDir, pkg} = packageInfo;
+
+  const board = await ideUtilities.getOrSelectTargetBoard();
+  if (!board) {
+    return;
+  }
+
+  // Below, we create compilation database based on the project and the board.
+  // Generating the database is time consuming involving execution of external
+  // processes, so we ensure it to run only one at a time using the manager.
+  await manager.offer(async () => {
+    // TODO(oka): Show that compilation is in progress in status bar.
+    try {
+      await commonUtil.exec('cros_workon', ['--board', board, 'start', pkg],
+          ideUtilities.getLogger().append);
+
+      await commonUtil.exec('env',
+          ['USE=compilation_database', `emerge-${board}`, pkg],
+          ideUtilities.getLogger().append, {logStdout: true});
+
+      // Make the generated compilation database available from clangd.
+      await commonUtil.exec(
+          'ln', ['-sf', `/build/${board}/build/compilation_database/` +
+        `${pkg}/compile_commands_chroot.json`,
+          path.join(MNT_HOST_SOURCE, sourceDir, 'compile_commands.json')],
+          ideUtilities.getLogger().append);
+    } catch (e) {
+      // TODO(oka): show error message for user to manually resolve problem
+      // (e.g. compile error).
+      ideUtilities.getLogger().appendLine((e as Error).message);
+      console.error(e);
+    }
+  });
+}
+
+// Known source code location to package name mapping which supports
+// compilation database generation.
+const KNOWN_PACKAGES: Array<PackageInfo> = [
+  ['src/aosp/frameworks/ml', 'chromeos-base/aosp-frameworks-ml-nn'],
+  ['src/aosp/frameworks/ml/chromeos/tests',
+    'chromeos-base/aosp-frameworks-ml-nn-vts'],
+  ['src/platform2/camera/android', 'chromeos-base/cros-camera-android-deps'],
+  ['src/platform2/camera/camera3_test', 'media-libs/cros-camera-test'],
+  ['src/platform2/camera/common', 'chromeos-base/cros-camera-libs'],
+  ['src/platform2/camera/common/jpeg/libjea_test',
+    'media-libs/cros-camera-libjea_test'],
+  ['src/platform2/camera/common/libcamera_connector_test',
+    'media-libs/cros-camera-libcamera_connector_test'],
+  ['src/platform2/camera/features/document_scanning',
+    'media-libs/cros-camera-document-scanning-test'],
+  ['src/platform2/camera/hal_adapter', 'chromeos-base/cros-camera'],
+  ['src/platform2/camera/hal/usb', 'media-libs/cros-camera-hal-usb'],
+  ['src/platform2/camera/hal/usb/tests', 'media-libs/cros-camera-usb-tests'],
+  ['src/platform2/camera/tools/cros_camera_tool',
+    'chromeos-base/cros-camera-tool'],
+  ['src/platform2/cros-disks', 'chromeos-base/cros-disks'],
+  ['src/platform2/hps', 'chromeos-base/hpsd'],
+  ['src/platform2/hps/util', 'chromeos-base/hps-tool'],
+  ['src/platform2/lorgnette', 'chromeos-base/lorgnette'],
+  ['src/platform2/shill', 'chromeos-base/shill'],
+  ['src/platform2/vm_tools', 'chromeos-base/vm_host_tools'],
+].map(([sourceDir, pkg]) => {
+  return {
+    sourceDir,
+    pkg,
+  };
+});
+Object.freeze(KNOWN_PACKAGES);
+
+// Get information of the package that would compile the file and generates
+// compilation database, or null if no such package is known.
+export async function getPackage(filepath: string,
+    mntHostSource: string = MNT_HOST_SOURCE): Promise<PackageInfo | null> {
+  let realpath = '';
+  try {
+    realpath = await fs.promises.realpath(filepath);
+  } catch (_e) {
+    return null;
+  }
+  const relPath = path.relative(mntHostSource, realpath);
+  if (relPath.startsWith('..') || path.isAbsolute(relPath)) {
+    return null;
+  }
+  let res = null;
+  for (const pkg of KNOWN_PACKAGES) {
+    if (relPath.startsWith(pkg.sourceDir + '/') &&
+      (res === null || res.sourceDir.length < pkg.sourceDir.length)) {
+      res = pkg;
+    }
+  }
+  return res;
+}
diff --git a/ide_tooling/cros-ide/src/cros_lint.ts b/ide_tooling/cros-ide/src/cros_lint.ts
new file mode 100644
index 0000000..6ba4036
--- /dev/null
+++ b/ide_tooling/cros-ide/src/cros_lint.ts
@@ -0,0 +1,157 @@
+// Copyright 2022 The Chromium OS 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 * as childProcess from 'child_process';
+import * as vscode from 'vscode';
+
+export function activate(context: vscode.ExtensionContext) {
+  const collection = vscode.languages.createDiagnosticCollection('cros-lint');
+  if (vscode.window.activeTextEditor) {
+    updateCrosLintDiagnostics(
+        vscode.window.activeTextEditor.document, collection);
+  }
+  context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(
+      editor => {
+        if (editor) {
+          updateCrosLintDiagnostics(editor.document, collection);
+        }
+      }));
+  context.subscriptions.push(vscode.workspace.onDidSaveTextDocument(
+      document => {
+        updateCrosLintDiagnostics(document, collection);
+      }));
+  context.subscriptions.push(vscode.workspace.onDidCloseTextDocument(
+      document => {
+        collection.delete(document.uri);
+      }));
+}
+
+// Describes how to run a linter and parse its output.
+interface LintConfig {
+  command(path: string) : string;
+  parse(stdout: string, stderr: string, document: vscode.TextDocument)
+      : vscode.Diagnostic[];
+}
+
+const GNLINT_PATH = '~/chromiumos/src/platform2/common-mk/gnlint.py';
+
+// Don't forget to update package.json when adding more languages.
+const lintConfigs = new Map<string, LintConfig>([
+  ['cpp', {
+    command: (path: string) => `cros lint ${path}`,
+    parse: parseCrosLintCpp,
+  }],
+  ['gn', {
+    command: (path: string) => GNLINT_PATH + ` ${path}`,
+    parse: parseCrosLintGn,
+  }],
+  ['python', {
+    command: (path: string) => `cros lint ${path}`,
+    parse: parseCrosLintShellPython,
+  }],
+  ['shellscript', {
+    command: (path: string) => `cros lint --output=parseable ${path}`,
+    parse: parseCrosLintShellPython,
+  }],
+]);
+
+function updateCrosLintDiagnostics(
+    document: vscode.TextDocument,
+    collection: vscode.DiagnosticCollection): void {
+  if (document && document.uri.scheme === 'file') {
+    const lintConfig = lintConfigs.get(document.languageId);
+    if (lintConfig) {
+      childProcess.exec(lintConfig.command(document.uri.fsPath),
+          (_error, stdout, stderr) => {
+            const diagnostics = lintConfig.parse(stdout, stderr, document);
+            collection.set(document.uri, diagnostics);
+          });
+    }
+  } else {
+    collection.clear();
+  }
+}
+
+export function parseCrosLintCpp(
+    stdout: string, stderr: string, document: vscode.TextDocument)
+  :vscode.Diagnostic[] {
+  const lineRE = /^([^ \n]+):([0-9]+):  (.*)  \[([^ ]+)\] \[([1-5])\]/gm;
+  const diagnostics: vscode.Diagnostic[] = [];
+  let match: RegExpExecArray | null;
+  // stdout and stderr are merged, because we saw that warnings can go to
+  // either.
+  // TODO(b/214322467): Figure out when we should use stderr and when stdout.
+  while ((match = lineRE.exec(stdout + '\n' + stderr)) !== null) {
+    const file = match[1];
+    let line = Number(match[2]);
+    // Warning about missing copyright is reported at hard coded line 0.
+    // This seems like a bug in cpplint.py, which otherwise uses 1-based
+    // line numbers.
+    if (line === 0) {
+      line = 1;
+    }
+    const message = match[3];
+    if (file === document.uri.fsPath) {
+      diagnostics.push(createDiagnostic(message, line));
+    }
+  }
+  return diagnostics;
+}
+
+// Parse output from platform2/common-mk/gnlint.py on a GN file.
+export function parseCrosLintGn(_stdout: string, stderr: string, document: vscode.TextDocument)
+: vscode.Diagnostic[] {
+  // Only the errors that have location in the file are captured.
+  // There are two categories of errors without line/column number:
+  // - file not formatted by gn-format: should do auto-format upon save
+  // - wrong commandline arguments: should be covered by extension unit test
+  // So these are ignored.
+  const lineRE = /ERROR: ([^ \n\:]+):([0-9]+):([0-9]+): (.*)/gm;
+  const diagnostics: vscode.Diagnostic[] = [];
+  let match: RegExpExecArray | null;
+  while ((match = lineRE.exec(stderr)) !== null) {
+    const file = match[1];
+    const line = Number(match[2]);
+    const startCol = Number(match[3]);
+    const message = match[4];
+    if (file === document.uri.fsPath) {
+      diagnostics.push(createDiagnostic(message, line, startCol));
+    }
+  }
+  return diagnostics;
+}
+
+// Parse output from cros lint on Python files
+// or cros lint --output=parseable on shell files.
+// TODO(b/214322467): Add unit tests for Python and shell.
+export function parseCrosLintShellPython(
+    stdout: string, _stderr: string, document: vscode.TextDocument)
+  : vscode.Diagnostic[] {
+  const lineRE = /^([^ \n\:]+):([0-9]+):([0-9]+): (.*)/gm;
+  const diagnostics: vscode.Diagnostic[] = [];
+  let match: RegExpExecArray | null;
+  while ((match = lineRE.exec(stdout)) !== null) {
+    const file = match[1];
+    const line = Number(match[2]);
+    const startCol = Number(match[3]);
+    const message = match[4];
+    if (file === document.uri.fsPath) {
+      diagnostics.push(createDiagnostic(message, line, startCol));
+    }
+  }
+  return diagnostics;
+}
+
+function createDiagnostic(message : string, line: number, startCol?: number)
+  : vscode.Diagnostic {
+  return new vscode.Diagnostic(
+      new vscode.Range(
+          new vscode.Position(line - 1, startCol ? startCol : 0),
+          new vscode.Position(line - 1, Number.MAX_VALUE),
+      ),
+      message,
+      // TODO(b/214322467): Should these actually be errors when they block
+      // repo upload?
+      vscode.DiagnosticSeverity.Warning,
+  );
+}
diff --git a/ide_tooling/cros-ide/src/dut_management/dut_manager.ts b/ide_tooling/cros-ide/src/dut_management/dut_manager.ts
new file mode 100644
index 0000000..ff75987
--- /dev/null
+++ b/ide_tooling/cros-ide/src/dut_management/dut_manager.ts
@@ -0,0 +1,218 @@
+// Copyright 2022 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * This contains the GUI and functionality for managing DUTs
+ */
+import * as vscode from 'vscode';
+import * as commonUtil from '../common/common_util';
+import * as ideutil from '../ide_utilities';
+import * as fleetProvider from './services/fleet_devices_provider';
+import * as vnc from './services/vnc_session';
+import * as localProvider from './services/local_devices_provider';
+
+type Tag = {
+  key: string;
+  value?: string;
+};
+
+type Build = {
+  id: string;
+  createdBy: string;
+  createTime: string;
+  startTime: string;
+  status: string;
+  tags: Tag[];
+};
+
+type DUT = {
+  Hostname: string;
+};
+
+type Lease = {
+  Build: Build;
+  DUT: DUT;
+};
+
+export type Leases = {
+  Leases: Lease[];
+};
+
+export class DeviceInfo extends vscode.TreeItem {
+  constructor(host: string, version: string) {
+    super(host, vscode.TreeItemCollapsibleState.None);
+    this.description = version;
+    this.iconPath = new vscode.ThemeIcon('device-desktop');
+  }
+}
+
+export async function activateDutManager(context: vscode.ExtensionContext) {
+  try {
+    // We need 'version', because without args crosfleet exits with error 2.
+    await commonUtil.exec('crosfleet', ['version']);
+  } catch (error) {
+    vscode.window.showWarningMessage(`DUT manager will not work,` +
+        ` because running 'crosfleet' failed: ${error}`);
+    return;
+  }
+
+  const staticDevicesProvider = new localProvider.LocalDevicesProvider();
+  const fleetDevicesProvider = new fleetProvider.FleetDevicesProvider();
+  const sessions = new Map<string, vnc.VncSession>();
+
+  context.subscriptions.push(
+      vscode.commands.registerCommand('cros-ide.connectToHostForScreen',
+          async (host?: string) => {
+            // If the command is selected directly from the command palette,
+            // prompt the user for the host to connect to.
+            if (!host) {
+              host = await promptHost('Connect to Host');
+              if (!host) {
+                return;
+              }
+            }
+
+            // If there's an existing session, just reveal its panel.
+            const existingSession = sessions.get(host);
+            if (existingSession) {
+              existingSession.revealPanel();
+              return;
+            }
+
+            // Create a new session and store it to sessions.
+            const newSession = new vnc.VncSession(host, context.extensionUri);
+            sessions.set(host, newSession);
+            newSession.onDidDispose(() => {
+              sessions.delete(host!);
+            });
+          }),
+      vscode.commands.registerCommand('cros-ide.connectToHostForShell',
+          async (host?: string) => {
+            // If the command is selected directly from the command palette,
+            // prompt the user for the host to connect to.
+            if (!host) {
+              host = await promptHost('Connect to Host');
+              if (!host) {
+                return;
+              }
+            }
+
+            // Create a new terminal.
+            const terminal = ideutil.createTerminalForHost(
+                host, 'CrOS: Shell', context.extensionUri, '');
+            terminal.show();
+          }),
+      vscode.commands.registerCommand('cros-ide.addHost',
+          async () => {
+            const host = await promptHost('Add New Host');
+            if (!host) {
+              return;
+            }
+
+            const configRoot = ideutil.getConfigRoot();
+            const hosts = configRoot.get<string[]>('hosts') || [];
+            hosts.push(host);
+            configRoot.update(
+                'hosts', hosts, vscode.ConfigurationTarget.Global);
+          }),
+      vscode.commands.registerCommand('cros-ide.deleteHost',
+          async (host?: string) => {
+            // If the command is selected directly from the command palette,
+            // prompt the user for the host to connect to.
+            if (!host) {
+              host = await promptHost('Delete Host');
+              if (!host) {
+                return;
+              }
+            }
+
+            // Try deleting crossfleet first. If not found, then try deleting
+            // from "my devices"
+            if (!fleetDevicesProvider.removeTreeItem(host)) {
+              const configRoot = ideutil.getConfigRoot();
+              const oldHosts = configRoot.get<string[]>('hosts') || [];
+              const newHosts = oldHosts.filter((h) => (h !== host));
+              configRoot.update(
+                  'hosts', newHosts, vscode.ConfigurationTarget.Global);
+            }
+          }),
+      vscode.commands.registerCommand('cros-ide.refreshCrosfleet',
+          () => {
+            fleetDevicesProvider.updateCache();
+          }),
+      vscode.commands.registerCommand('cros-ide.addFleetHost',
+          async () => {
+            const board = await promptBoard('Model');
+            await crosfleetDutLease({board});
+            // HACK: copy over binaries.
+            // TODO: Removing prebuilts till we have an alterative solution
+            // const prebuilt = vscode.Uri.joinPath(
+            //     context.extensionUri, 'resources', 'novnc-prebuilt.tar.gz');
+            // await util.execFile(
+            //     `ssh ${lease.DUT.Hostname + '.cros'} ` +
+            //     `tar xz -C /usr/local < ${prebuilt.fsPath}`);
+            // fleetDevicesProvider.updateCache();
+          }),
+      vscode.workspace.onDidChangeConfiguration((e) => {
+        if (e.affectsConfiguration('cros')) {
+          staticDevicesProvider.onConfigChanged();
+        }
+      }),
+      vscode.window.registerTreeDataProvider(
+          'static-devices', staticDevicesProvider),
+      vscode.window.registerTreeDataProvider(
+          'fleet-devices', fleetDevicesProvider),
+  );
+}
+
+async function promptHost(title: string): Promise<string | undefined> {
+  return await vscode.window.showInputBox({
+    title: title,
+    placeHolder: 'host[:port]',
+  });
+}
+
+async function promptBoard(title: string): Promise<string | undefined> {
+  return await vscode.window.showInputBox({
+    title: title,
+    placeHolder: 'board',
+  });
+}
+
+// TODO(lokeric): remove this code if unnecessary.
+/*
+function crosfleetBoard(lease: Lease): string | undefined {
+  for (const tag of lease.Build.tags) {
+    if (tag.key === 'label-board') {
+      return tag.value;
+    }
+  }
+  return undefined;
+}
+*/
+
+type LeaseOpts = {
+  board?: string;
+  // dev?: boolean;
+  // dims?: {key: string, value: string}[];
+  // host?: string;
+  minutes?: number;
+  // model?: string;
+  reason?: string;
+};
+
+async function crosfleetDutLease(opts?: LeaseOpts): Promise<Lease> {
+  const args = ['dut', 'lease', '-json'];
+  if (opts?.board !== undefined) {
+    args.push('-board', opts?.board);
+  }
+  if (opts?.minutes !== undefined) {
+    args.push('-minutes', opts?.minutes.toFixed(0));
+  }
+  if (opts?.reason !== undefined) {
+    args.push('-reason', opts?.reason);
+  }
+  const out = await commonUtil.exec('crosfleet', args);
+  return JSON.parse(out) as Lease;
+}
diff --git a/ide_tooling/cros-ide/src/dut_management/services/dut_services.ts b/ide_tooling/cros-ide/src/dut_management/services/dut_services.ts
new file mode 100644
index 0000000..dc60056
--- /dev/null
+++ b/ide_tooling/cros-ide/src/dut_management/services/dut_services.ts
@@ -0,0 +1,35 @@
+// Copyright 2022 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * Common libs specific to DUT management.
+ */
+import * as commonUtil from '../../common/common_util';
+import * as ideutil from '../../ide_utilities';
+import * as dutManager from '../dut_manager';
+
+const BUILDER_PATH_RE = /CHROMEOS_RELEASE_BUILDER_PATH=(.*)/;
+
+export async function crosfleetLeases(): Promise<dutManager.Leases> {
+  const out = await commonUtil.exec('crosfleet', ['dut', 'leases', '-json']);
+  // TODO: validation...
+  const leases = JSON.parse(out) as dutManager.Leases;
+  if (!leases.Leases) {
+    leases.Leases = [];
+  }
+  return leases;
+}
+
+export async function queryHostVersion(host: string): Promise<string> {
+  const output = await ideutil.runSSH(host, ['cat', '/etc/lsb-release']);
+  const match = BUILDER_PATH_RE.exec(output);
+  if (!match) {
+    throw new Error(`Failed to connect to ${host}`);
+  }
+  return match[1];
+}
+
+export async function crosfleetDutAbandon(host: string) {
+  await commonUtil.exec('crosfleet', ['dut', 'abandon', host]);
+}
diff --git a/ide_tooling/cros-ide/src/dut_management/services/fleet_devices_provider.ts b/ide_tooling/cros-ide/src/dut_management/services/fleet_devices_provider.ts
new file mode 100644
index 0000000..7202204
--- /dev/null
+++ b/ide_tooling/cros-ide/src/dut_management/services/fleet_devices_provider.ts
@@ -0,0 +1,87 @@
+// Copyright 2022 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * Manages Leased Devices
+ */
+import * as vscode from 'vscode';
+import * as ideutil from '../../ide_utilities';
+import * as dutManager from '../dut_manager';
+import * as dutServices from './dut_services';
+
+type CrosfleetDutInfo = {
+  hostname: string;
+  version?: string;
+};
+
+export class FleetDevicesProvider implements vscode.TreeDataProvider<string> {
+  private leases: Map<string, CrosfleetDutInfo>;
+
+  private onDidChangeTreeDataEmitter =
+    new vscode.EventEmitter<string | undefined | null | void>();
+  readonly onDidChangeTreeData = this.onDidChangeTreeDataEmitter.event;
+
+  constructor() {
+    this.leases = new Map();
+    this.updateCache();
+  }
+
+  async updateCache() {
+    // TODO: animations while we are loading?
+    // Query duts.
+    const leases = await dutServices.crosfleetLeases();
+    this.leases = new Map(leases.Leases.map(l => [
+      l.DUT.Hostname + '.cros',
+      {
+        hostname: l.DUT.Hostname + '.cros',
+      },
+    ]));
+    this.onDidChangeTreeDataEmitter.fire();
+
+    // Update versions in parallel.
+    for (const dut of this.leases.values()) {
+      if (dut.version !== undefined) {
+        continue;
+      }
+      (async () => {
+        let version = '???';
+        try {
+          version = await dutServices.queryHostVersion(dut.hostname);
+        } catch (_) { }
+        dut.version = version;
+        this.onDidChangeTreeDataEmitter.fire();
+      })().catch((e) => { });
+    }
+  }
+
+  async removeTreeItem(host: string): Promise<boolean> {
+    if (this.leases.delete(host)) {
+      await dutServices.crosfleetDutAbandon(host);
+      this.onDidChangeTreeDataEmitter.fire();
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  getTreeItem(host: string): dutManager.DeviceInfo {
+    return new dutManager.DeviceInfo(
+        host, this.leases.get(host)?.version || '');
+  }
+
+  getChildren(parent?: string): string[] {
+    if (parent) {
+      return [];
+    }
+    return [...this.leases.keys()];
+  }
+
+  private queryDuts(): void {
+    dutServices.crosfleetLeases().then();
+  }
+
+  private getHosts(): string[] {
+    return ideutil.getConfigRoot().get<string[]>('hosts') || [];
+  }
+}
diff --git a/ide_tooling/cros-ide/src/dut_management/services/local_devices_provider.ts b/ide_tooling/cros-ide/src/dut_management/services/local_devices_provider.ts
new file mode 100644
index 0000000..395b71a
--- /dev/null
+++ b/ide_tooling/cros-ide/src/dut_management/services/local_devices_provider.ts
@@ -0,0 +1,61 @@
+// Copyright 2022 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * Manages Local Devices
+ */
+import * as vscode from 'vscode';
+import * as ideutil from '../../ide_utilities';
+import * as dutManager from '../dut_manager';
+import * as dutServices from './dut_services';
+
+export class LocalDevicesProvider implements vscode.TreeDataProvider<string> {
+  private readonly cachedVersions = new Map<string, string>();
+
+  private onDidChangeTreeDataEmitter =
+    new vscode.EventEmitter<string | undefined | null | void>();
+  readonly onDidChangeTreeData = this.onDidChangeTreeDataEmitter.event;
+
+  constructor() {
+    this.queryVersions();
+  }
+
+  getTreeItem(host: string): dutManager.DeviceInfo {
+    return new dutManager.DeviceInfo(host, this.cachedVersions.get(host) || '');
+  }
+
+  getChildren(parent?: string): string[] {
+    if (parent) {
+      return [];
+    }
+    return this.getHosts();
+  }
+
+  onConfigChanged(): void {
+    this.queryVersions();
+    this.onDidChangeTreeDataEmitter.fire();
+    // Async, query crosfleet if it exists
+    // Refire emitter when we get results in
+  }
+
+  private queryVersions(): void {
+    for (const host of this.getHosts()) {
+      if (this.cachedVersions.has(host)) {
+        continue;
+      }
+      (async () => {
+        let version = '???';
+        try {
+          version = await dutServices.queryHostVersion(host);
+        } catch (_) { }
+        this.cachedVersions.set(host, version);
+        this.onDidChangeTreeDataEmitter.fire();
+      })().catch((e) => { });
+    }
+  }
+
+  private getHosts(): string[] {
+    return ideutil.getConfigRoot().get<string[]>('hosts') || [];
+  }
+}
diff --git a/ide_tooling/cros-ide/src/dut_management/services/vnc_session.ts b/ide_tooling/cros-ide/src/dut_management/services/vnc_session.ts
new file mode 100644
index 0000000..b11f761
--- /dev/null
+++ b/ide_tooling/cros-ide/src/dut_management/services/vnc_session.ts
@@ -0,0 +1,116 @@
+// Copyright 2022 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * Represents a VNC Session
+ */
+import * as vscode from 'vscode';
+import * as ideutil from '../../ide_utilities';
+
+export class VncSession {
+  private static nextAvailablePort = 6080;
+
+  private readonly localPort: number;
+  private readonly terminal: vscode.Terminal;
+  private readonly panel: vscode.WebviewPanel;
+  private disposed = false;
+
+  private onDidDisposeEmitter = new vscode.EventEmitter<void>();
+  readonly onDidDispose = this.onDidDisposeEmitter.event;
+
+  constructor(private readonly host: string,
+              readonly extensionUri: vscode.Uri) {
+    // Here we do the following:
+    // 1. Choose a local port
+    // 2. Start an SSH session for SSH tunnel and to start kmsvnc and novnc
+    // 3. Create tab to display VNC contents
+    this.localPort = VncSession.nextAvailablePort++;
+    this.terminal =
+        VncSession.startVncServer(host, this.localPort, extensionUri);
+    this.panel = VncSession.createWebview(host, this.localPort);
+
+    // Dispose the session when the panel is closed.
+    this.panel.onDidDispose(() => {
+      this.dispose();
+    });
+  }
+
+  dispose(): void {
+    if (this.disposed) {
+      return;
+    }
+    this.disposed = true;
+
+    this.terminal.dispose();
+    this.panel.dispose();
+    this.onDidDisposeEmitter.fire();
+  }
+
+  revealPanel(): void {
+    this.panel.reveal();
+  }
+
+  private static startVncServer(host: string, localPort: number,
+      extensionUri: vscode.Uri): vscode.Terminal {
+    const terminal =ideutil.createTerminalForHost(host,
+        'CrOS: VNC forwarding', extensionUri, `-L ${localPort}:localhost:6080`);
+    terminal.sendText('fuser -k 5900/tcp 6080/tcp');
+    terminal.sendText('kmsvnc &');
+    terminal.sendText('novnc &');
+    return terminal;
+  }
+
+  private static createWebview(
+      host: string, localPort: number): vscode.WebviewPanel {
+    const panel = vscode.window.createWebviewPanel(
+        'vncclient',
+        `CrOS VNC Client: ${host}`,
+        vscode.ViewColumn.One,
+        {
+          enableScripts: true,
+          // https://code.visualstudio.com/api/extension-guides/webview#retaincontextwhenhidden
+          retainContextWhenHidden: true,
+        },
+    );
+    panel.webview.html = VncSession.getWebviewContent(localPort);
+    return panel;
+  }
+
+  private static getWebviewContent(localPort: number) {
+    return `<!DOCTYPE html>
+    <html lang="en">
+    <head>
+      <meta charset="UTF-8">
+      <meta name="viewport" content="width=device-width, initial-scale=1.0">
+      <title>CrOS VNC Client</title>
+      <style>
+        html, body {
+          margin: 0;
+          padding: 0;
+          height: 100%;
+        }
+        #main {
+          border: 0;
+          width: 100%;
+          height: 100%;
+        }
+      </style>
+    </head>
+    <body>
+      <iframe
+        id="main"
+        title="iframe"
+        sandbox="allow-scripts allow-same-origin">
+      </iframe>
+      <script>
+        // Navigate after 5 seconds.
+        setTimeout(() => {
+          document.getElementById('main').src =
+              'http://localhost:${localPort}/vnc.html?resize=scale&autoconnect=true';
+        }, 5000);
+      </script>
+    </body>
+    </html>`;
+  }
+}
diff --git a/ide_tooling/cros-ide/src/extension.ts b/ide_tooling/cros-ide/src/extension.ts
new file mode 100644
index 0000000..a62673e
--- /dev/null
+++ b/ide_tooling/cros-ide/src/extension.ts
@@ -0,0 +1,35 @@
+// Copyright 2022 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * This is the main entry point for the vsCode plugin.
+ *
+ * Keep this minimal - breakout GUI and App-Behavior to separate files.
+ */
+import * as vscode from 'vscode';
+import * as boardsPackages from './boards_packages';
+import * as codesearch from './codesearch';
+import * as coverage from './coverage';
+import * as cppCodeCompletion from './cpp_code_completion';
+import * as crosLint from './cros_lint';
+import * as dutManager from './dut_management/dut_manager';
+import * as ideUtilities from './ide_utilities';
+import * as shortLinkProvider from './short_link_provider';
+import * as targetBoard from './target_board';
+import * as workon from './workon';
+
+export function activate(context: vscode.ExtensionContext) {
+  dutManager.activateDutManager(context);
+  crosLint.activate(context);
+  boardsPackages.activate();
+  shortLinkProvider.activate(context);
+  codesearch.activate(context);
+  workon.activate(context);
+  cppCodeCompletion.activate(context);
+  targetBoard.activate(context);
+
+  if (ideUtilities.getConfigRoot().get<boolean>('features.testCoverage')) {
+    coverage.activate(context);
+  }
+}
diff --git a/ide_tooling/cros-ide/src/ide_utilities.ts b/ide_tooling/cros-ide/src/ide_utilities.ts
new file mode 100644
index 0000000..a4bbdb1
--- /dev/null
+++ b/ide_tooling/cros-ide/src/ide_utilities.ts
@@ -0,0 +1,110 @@
+// Copyright 2022 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * Keep all general utility functions here, or in common_util.
+ */
+import * as vscode from 'vscode';
+import * as childProcess from 'child_process';
+import * as cros from './common/cros';
+
+export function runSSH(host: string, args: string[]): Promise<string> {
+  return new Promise((resolve, reject) => {
+    childProcess.execFile('ssh', [host].concat(args), (error, stdout) => {
+      if (error) {
+        reject(error);
+        return;
+      }
+      resolve(stdout);
+    });
+  });
+}
+
+export function getConfigRoot(): vscode.WorkspaceConfiguration {
+  return vscode.workspace.getConfiguration('cros-ide');
+}
+
+export function createTerminalForHost(
+    host: string, namePrefix: string, extensionUri: vscode.Uri,
+    extraOptions: string): vscode.Terminal {
+  const testingRsa =
+      vscode.Uri.joinPath(extensionUri, 'resources', 'testing_rsa');
+  const terminal = vscode.window.createTerminal(`${namePrefix} ${host}`);
+  const splitHost = host.split(':');
+  let portOption = '';
+  if (splitHost.length === 2) {
+    host = splitHost[0];
+    portOption = `-p ${splitHost[1]}`;
+  }
+  terminal.sendText(
+      `ssh -i ${testingRsa.fsPath} ${extraOptions} ${portOption} ` +
+      `root@${host}; exit $?`);
+  return terminal;
+}
+
+const loggerInstance = vscode.window.createOutputChannel('cros');
+export function getLogger(): vscode.OutputChannel {
+  return loggerInstance;
+}
+
+// Config section name for the target board.
+export const BOARD = 'board';
+
+export async function getOrSelectTargetBoard(): Promise<string | null> {
+  const board = getConfigRoot().get<string>(BOARD);
+  if (board) {
+    return board;
+  }
+  return await selectAndUpdateTargetBoard({suggestMostRecent: true});
+}
+
+/**
+ * Ask user to select the board to use. If user selects a board, the config
+ * is updated with the board name.
+ *
+ * @params config If config.suggestMostRecent is true, the board most recently
+ * used is proposed to the user, before showing the board picker.
+ *
+ * TODO(oka): unit test this function (consider stubbing vscode APIs).
+ */
+export async function selectAndUpdateTargetBoard(
+    config: {suggestMostRecent: boolean}): Promise<string | null> {
+  const boards = await cros.getSetupBoards();
+  if (boards.length === 0) {
+    await vscode.window.showErrorMessage('No board has been setup; run ' +
+        'setup_board for a board you want to work on.');
+    return null;
+  }
+  const mostRecent = boards[0];
+
+  if (config.suggestMostRecent) {
+    const selection = await vscode.window.showWarningMessage(
+        `Target board is not set. Do you use ${mostRecent}?`, {
+          title: 'Yes',
+        }, {
+          title: 'Customize',
+        });
+    if (!selection) {
+      return null;
+    }
+    switch (selection.title) {
+      case 'Yes':
+        await getConfigRoot().update(BOARD, mostRecent);
+        return mostRecent;
+      case 'Customize':
+        break;
+      default:
+        return null;
+    }
+  }
+
+  const board = await vscode.window.showQuickPick(boards, {
+    title: 'Target board',
+  }) || null;
+  if (!board) {
+    return null;
+  }
+  await getConfigRoot().update(BOARD, board);
+  return board;
+}
diff --git a/ide_tooling/cros-ide/src/short_link_provider.ts b/ide_tooling/cros-ide/src/short_link_provider.ts
new file mode 100644
index 0000000..e588ffc
--- /dev/null
+++ b/ide_tooling/cros-ide/src/short_link_provider.ts
@@ -0,0 +1,99 @@
+// Copyright 2022 The Chromium OS 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 * as vscode from 'vscode';
+
+export function activate(context: vscode.ExtensionContext) {
+  context.subscriptions.push(
+      vscode.languages.registerDocumentLinkProvider(
+          '*',
+          new ShortLinkProvider()));
+}
+
+/**
+ * Tell VS Code that things like go/example, crbug/123456 are links.
+ *
+ * We also support bugs referenced with chromium:xxxxxx and b:xxxxxx,
+ * as well as ldaps in todos, which link to the teams page.
+ */
+export class ShortLinkProvider implements vscode.DocumentLinkProvider {
+  public provideDocumentLinks(
+      document: vscode.TextDocument, token: vscode.CancellationToken)
+    : vscode.ProviderResult<vscode.DocumentLink[]> {
+    // TODO(b/216429126): add caching
+    return this.extractLinks(document, shortLinkPattern, shortLinkUri)
+        .concat(
+            this.extractLinks(document, trackerBugPattern, trackerBugUri),
+            this.extractLinks(document, todoLdapPattern, todoLdapUri));
+  }
+
+  private extractLinks(
+      document: vscode.TextDocument,
+      pattern : RegExp,
+      generateUri: (match: RegExpMatchArray) => vscode.Uri,
+  ) : vscode.DocumentLink[] {
+    const links: vscode.DocumentLink[] = [];
+    const text = document.getText();
+    let match: RegExpMatchArray | null;
+    while ((match = pattern.exec(text)) !== null) {
+      // TODO(b/216429126): check when match.index can be undefined
+      if (match.index) {
+        const linkStart = document.positionAt(match.index);
+        const linkEnd = document.positionAt((match.index) + match[0].length);
+        links.push(new vscode.DocumentLink(
+            new vscode.Range(linkStart, linkEnd),
+            generateUri(match)));
+      }
+    }
+    return links;
+  }
+}
+
+// Keep regular expression in one line to work around Gerrit syntax
+// highlighting bug.
+/* eslint max-len: ["error", { "ignoreRegExpLiterals": true }]*/
+
+// Matches bugs references with chromium:xxxxxx and b:xxxxxx.
+// We start with lookahead for spaces, '(' and line start to avoid mathichg
+// things like MAC adderesses.
+//
+// For simplicity, we do not match #fragment, so b:123#comment3, will only
+// match b:123. Note that b/123#comment3 will work via the other pattern though.
+const trackerBugPattern = /(?<=^|\s|\()(b|chromium):([0-9]+)/g;
+
+// Extract the uri from matches to trackerBugPattern.
+function trackerBugUri(match: RegExpMatchArray): vscode.Uri {
+  let tracker = match[1];
+  if (tracker === 'chromium') {
+    tracker = 'crbug';
+  }
+  const id = match[2];
+  return vscode.Uri.parse(`http://${tracker}/${id}`);
+}
+
+// Matches ldaps in todos. Lookahead and lookbehind are used to restrict
+// the match to the ldap.
+const todoLdapPattern = /(?<=TODO\()([a-z]+)(?=\))/g;
+
+// Extract the uri from matches to todoLdapPattern.
+function todoLdapUri(match: RegExpMatchArray): vscode.Uri {
+  const ldap = match[1];
+  return vscode.Uri.parse(`http://teams/${ldap}`);
+}
+
+// Match (up-to-5-letters)[.com]/(path). There are two capturing groups:
+//   - host (for example, crbug), it may include '.com'
+//   - url (for example, 123456)
+// For robustness, the regex starts with a lookbehind matching one of:
+//  - start of line
+//  - whitespace
+//  - match to '(', because links are often used in "TODO(link)"
+const shortLinkPattern = /(?<=^|\s|\()\b([a-z]{1,5}(?:\.com)?)\/([^)\s.,;'\"]+)/g;
+
+// Extract the uri from matches to shortLinkPattern.
+function shortLinkUri(match: RegExpMatchArray): vscode.Uri {
+  const host = match[1];
+  const path = match[2];
+  return vscode.Uri.parse(`http://${host}/${path}`);
+}
diff --git a/ide_tooling/cros-ide/src/target_board.ts b/ide_tooling/cros-ide/src/target_board.ts
new file mode 100644
index 0000000..df81910
--- /dev/null
+++ b/ide_tooling/cros-ide/src/target_board.ts
@@ -0,0 +1,42 @@
+// Copyright 2022 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * Manages the target board config.
+ */
+
+import * as vscode from 'vscode';
+import * as ideUtilities from './ide_utilities';
+
+const BOARD_CONFIG = 'cros-ide.board';
+
+export function activate(context: vscode.ExtensionContext) {
+  const boardStatusBarItem = vscode.window.createStatusBarItem(
+      vscode.StatusBarAlignment.Left);
+  boardStatusBarItem.command = 'cros-ide.selectBoard';
+
+  context.subscriptions.push(vscode.workspace.onDidChangeConfiguration((
+      e: vscode.ConfigurationChangeEvent) => {
+    if (e.affectsConfiguration(BOARD_CONFIG)) {
+      updateBoardStatus(boardStatusBarItem);
+    }
+  }));
+  updateBoardStatus(boardStatusBarItem);
+
+  vscode.commands.registerCommand('cros-ide.selectBoard', () => {
+    ideUtilities.selectAndUpdateTargetBoard({suggestMostRecent: false})
+        .catch(console.error);
+  });
+}
+
+function updateBoardStatus(boardStatusBarItem: vscode.StatusBarItem) {
+  const board = ideUtilities.getConfigRoot().get<string>(
+      ideUtilities.BOARD) || '';
+  boardStatusBarItem.text = board;
+  if (board) {
+    boardStatusBarItem.show();
+  } else {
+    boardStatusBarItem.hide();
+  }
+}
diff --git a/ide_tooling/cros-ide/src/test/integration/cpp_code_completion.test.ts b/ide_tooling/cros-ide/src/test/integration/cpp_code_completion.test.ts
new file mode 100644
index 0000000..dd42673
--- /dev/null
+++ b/ide_tooling/cros-ide/src/test/integration/cpp_code_completion.test.ts
@@ -0,0 +1,37 @@
+// Copyright 2022 The Chromium OS 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 * as assert from 'assert';
+import * as path from 'path';
+import * as commonUtil from '../../common/common_util';
+import * as cppCodeCompletion from '../../cpp_code_completion';
+import * as testing from '../testing';
+
+suite('Code completion', () => {
+  test('Get package', async () => {
+    await commonUtil.withTempDir(async td => {
+      await testing.putFiles(td, {
+        '/mnt/host/source/src/platform2/cros-disks/foo.cc': 'x',
+        '/mnt/host/source/src/platform2/unknown_dir/foo.cc': 'x',
+      });
+      assert.deepStrictEqual(await cppCodeCompletion.getPackage(
+          path.join(td, '/mnt/host/source/src/platform2/cros-disks/foo.cc'),
+          path.join(td, '/mnt/host/source'),
+      ), {
+        sourceDir: 'src/platform2/cros-disks',
+        pkg: 'chromeos-base/cros-disks',
+      }, 'success');
+
+      assert.deepStrictEqual(await cppCodeCompletion.getPackage(
+          path.join(td, '/mnt/host/source/src/platform2/unknown_dir/foo.cc'),
+          path.join(td, '/mnt/host/source'),
+      ), null, 'unknown');
+
+      assert.deepStrictEqual(await cppCodeCompletion.getPackage(
+          path.join(td, '/mnt/host/source/not_exist'),
+          path.join(td, '/mnt/host/source'),
+      ), null, 'not exist');
+    });
+  });
+});
diff --git a/ide_tooling/cros-ide/src/test/integration/cros_lint.test.ts b/ide_tooling/cros-ide/src/test/integration/cros_lint.test.ts
new file mode 100644
index 0000000..f17b4b2
--- /dev/null
+++ b/ide_tooling/cros-ide/src/test/integration/cros_lint.test.ts
@@ -0,0 +1,196 @@
+// Copyright 2022 The Chromium OS 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 * as assert from 'assert';
+import * as vscode from 'vscode';
+
+import * as crosLint from '../../cros_lint';
+
+/* eslint max-len: ["error", { "ignoreTemplateLiterals": true }]*/
+
+const cppFileName = 'cros-disks/aaa.h';
+
+const cppFileContents =
+`#ifndef CROS_DISKS_AAA_H_
+#define CROS_DISKS_AAA_H_
+
+namespace {
+    int f();
+}
+
+#endif  // CROS_DISKS_AAA_H_
+`;
+
+const cppLintOutput =
+`cros-disks/aaa.h:0:  No copyright message found.  You should have a line: "Copyright [year] <Copyright Owner>"  [legal/copyright] [5]
+cros-disks/aaa.h:4:  Do not use unnamed namespaces in header files.  See https://google.github.io/styleguide/cppguide.html#Namespaces for more information.  [build/namespaces] [4]
+Done processing cros-disks/aaa.h
+Total errors found: 2
+11:21:52: ERROR: Found lint errors in 1 files.
+`;
+
+const pythonFileName = 'cros-disks/aaa.py';
+
+const pythonFileContents =
+`#!/usr/bin/env python3
+
+class Foo:
+    pass
+`;
+
+const pythonLintOutput =
+`************ Module aaa
+cros-disks/aaa.py:1:0: C9001: Modules should have docstrings (even a one liner) (module-missing-docstring)
+cros-disks/aaa.py:3:0: C9002: Classes should have docstrings (even a one liner) (class-missing-docstring)
+`;
+
+const shellFileName = 'cros-disks/aaa.sh';
+
+const shellFileContents =
+`#!/bin/bash
+
+echo $1
+`;
+
+const shellLintOutput =
+`cros-disks/aaa.sh:3:6: note: Double quote to prevent globbing and word splitting. [SC2086]
+`;
+
+const gnFileName = 'example/BUILD.gn';
+
+const gnFileContents =
+`executable("my_exec") {
+  ldflags = [ "-lm" ]
+  sources = [ "main.cc" ]
+}
+`;
+
+const gnLintOutput =
+`12:34:56.789: ERROR: **** example/BUILD.gn: found 3 issue(s)
+12:34:56.789: ERROR: CheckFormat: Needs reformatting. Run following command: /your_workdir/src/platform2/common-mk/../../../chroot/usr/bin/gn format example/BUILD.gn
+12:34:56.789: ERROR: example/BUILD.gn:2:15: GnLintLibFlags: Libraries should be specified by "libs", not -l flags in "ldflags": -lm
+12:34:56.789: ERROR: example/BUILD.gn:3:3: GnLintOrderingWithinTarget: wrong parameter order in executable(my_exec): put parameters in the following order: output_name/visibility/testonly, sources, other parameters, public_deps and deps
+12:34:56.789: ERROR: 1 file(s) failed linting
+`;
+
+/** Provides virtual documents for testing. */
+class TestDocumentProvider implements vscode.TextDocumentContentProvider {
+  constructor(
+    readonly files : Map<string, string>,
+  ) {}
+
+  provideTextDocumentContent(uri: vscode.Uri): string {
+    return this.files.get(uri.fsPath)!;
+  }
+}
+
+const documentProvider = new TestDocumentProvider(new Map<string, string>([
+  [cppFileName, cppFileContents],
+  [pythonFileName, pythonFileContents],
+  [shellFileName, shellFileContents],
+  [gnFileName, gnFileContents],
+]));
+const scheme = 'testing';
+vscode.workspace.registerTextDocumentContentProvider(scheme, documentProvider);
+
+suite('Cros Lint Test Suite', () => {
+  test('Cpp warnings', async () => {
+    const uri = vscode.Uri.from({scheme: scheme, path: cppFileName});
+    const textDocument = await vscode.workspace.openTextDocument(uri);
+    const actual = crosLint.parseCrosLintCpp(cppLintOutput, '', textDocument);
+    assert.strictEqual(actual.length, 2);
+    const expected = [
+      new vscode.Diagnostic(
+          new vscode.Range(
+              new vscode.Position(0, 0),
+              new vscode.Position(0, Number.MAX_VALUE),
+          ),
+          `No copyright message found.  You should have a line: "Copyright [year] <Copyright Owner>"`,
+          vscode.DiagnosticSeverity.Warning,
+      ),
+      new vscode.Diagnostic(
+          new vscode.Range(
+              new vscode.Position(3, 0),
+              new vscode.Position(3, Number.MAX_VALUE),
+          ),
+          `Do not use unnamed namespaces in header files.  See https://google.github.io/styleguide/cppguide.html#Namespaces for more information.`,
+          vscode.DiagnosticSeverity.Warning,
+      ),
+    ];
+    assert.deepStrictEqual(expected, actual);
+  });
+
+  test('Python warnings', async () => {
+    const uri = vscode.Uri.from({scheme: scheme, path: pythonFileName});
+    const textDocument = await vscode.workspace.openTextDocument(uri);
+    const actual =
+      crosLint.parseCrosLintShellPython(pythonLintOutput, '', textDocument);
+    assert.strictEqual(actual.length, 2);
+    const expected = [
+      new vscode.Diagnostic(
+          new vscode.Range(
+              new vscode.Position(0, 0),
+              new vscode.Position(0, Number.MAX_VALUE),
+          ),
+          `C9001: Modules should have docstrings (even a one liner) (module-missing-docstring)`,
+          vscode.DiagnosticSeverity.Warning,
+      ),
+      new vscode.Diagnostic(
+          new vscode.Range(
+              new vscode.Position(2, 0),
+              new vscode.Position(2, Number.MAX_VALUE),
+          ),
+          `C9002: Classes should have docstrings (even a one liner) (class-missing-docstring)`,
+          vscode.DiagnosticSeverity.Warning,
+      ),
+    ];
+    assert.deepStrictEqual(expected, actual);
+  });
+
+  test('Shell warnings', async () => {
+    const uri = vscode.Uri.from({scheme: scheme, path: shellFileName});
+    const textDocument = await vscode.workspace.openTextDocument(uri);
+    const actual =
+      crosLint.parseCrosLintShellPython(shellLintOutput, '', textDocument);
+    assert.strictEqual(actual.length, 1);
+    const expected = [
+      new vscode.Diagnostic(
+          new vscode.Range(
+              new vscode.Position(2, 6),
+              new vscode.Position(2, Number.MAX_VALUE),
+          ),
+          `note: Double quote to prevent globbing and word splitting. [SC2086]`,
+          vscode.DiagnosticSeverity.Warning,
+      ),
+    ];
+    assert.deepStrictEqual(expected, actual);
+  });
+
+  test('GN errors', async () => {
+    const uri = vscode.Uri.from({scheme: scheme, path: gnFileName});
+    const textDocument = await vscode.workspace.openTextDocument(uri);
+    const actual =
+      crosLint.parseCrosLintGn('', gnLintOutput, textDocument);
+    assert.strictEqual(actual.length, 2);
+    const expected = [
+      new vscode.Diagnostic(
+          new vscode.Range(
+              new vscode.Position(1, 15),
+              new vscode.Position(1, Number.MAX_VALUE),
+          ),
+          `GnLintLibFlags: Libraries should be specified by "libs", not -l flags in "ldflags": -lm`,
+          vscode.DiagnosticSeverity.Warning,
+      ),
+      new vscode.Diagnostic(
+          new vscode.Range(
+              new vscode.Position(2, 3),
+              new vscode.Position(2, Number.MAX_VALUE),
+          ),
+          `GnLintOrderingWithinTarget: wrong parameter order in executable(my_exec): put parameters in the following order: output_name/visibility/testonly, sources, other parameters, public_deps and deps`,
+          vscode.DiagnosticSeverity.Warning,
+      ),
+    ];
+    assert.deepStrictEqual(expected, actual);
+  });
+});
diff --git a/ide_tooling/cros-ide/src/test/integration/extension.test.ts b/ide_tooling/cros-ide/src/test/integration/extension.test.ts
new file mode 100644
index 0000000..81f271a
--- /dev/null
+++ b/ide_tooling/cros-ide/src/test/integration/extension.test.ts
@@ -0,0 +1,18 @@
+// Copyright 2022 The Chromium OS 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 * as assert from 'assert';
+
+// You can import and use all API from the 'vscode' module
+// as well as import your extension to test it
+import * as vscode from 'vscode';
+// import * as myExtension from '../../extension';
+
+suite('Extension Test Suite', () => {
+  vscode.window.showInformationMessage('Start all tests.');
+
+  test('Sample test', () => {
+    assert.strictEqual(-1, [1, 2, 3].indexOf(5));
+    assert.strictEqual(-1, [1, 2, 3].indexOf(0));
+  });
+});
diff --git a/ide_tooling/cros-ide/src/test/integration/index.ts b/ide_tooling/cros-ide/src/test/integration/index.ts
new file mode 100644
index 0000000..ff27c84
--- /dev/null
+++ b/ide_tooling/cros-ide/src/test/integration/index.ts
@@ -0,0 +1,41 @@
+// Copyright 2022 The Chromium OS 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 * as path from 'path';
+import * as Mocha from 'mocha';
+import * as glob from 'glob';
+
+export function run(): Promise<void> {
+  // Create the mocha test
+  const mocha = new Mocha({
+    ui: 'tdd',
+    color: true,
+  });
+
+  const testsRoot = path.resolve(__dirname, '..');
+
+  return new Promise((c, e) => {
+    glob('**/**.test.js', {cwd: testsRoot}, (err, files) => {
+      if (err) {
+        return e(err);
+      }
+
+      // Add files to the test suite
+      files.forEach(f => mocha.addFile(path.resolve(testsRoot, f)));
+
+      try {
+        // Run the mocha test
+        mocha.run(failures => {
+          if (failures > 0) {
+            e(new Error(`${failures} tests failed.`));
+          } else {
+            c();
+          }
+        });
+      } catch (err) {
+        console.error(err);
+        e(err);
+      }
+    });
+  });
+}
diff --git a/ide_tooling/cros-ide/src/test/integration/short_link_provider.test.ts b/ide_tooling/cros-ide/src/test/integration/short_link_provider.test.ts
new file mode 100644
index 0000000..86042c7
--- /dev/null
+++ b/ide_tooling/cros-ide/src/test/integration/short_link_provider.test.ts
@@ -0,0 +1,150 @@
+// Copyright 2022 The Chromium OS 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 * as assert from 'assert';
+import * as vscode from 'vscode';
+
+import * as shortLinkProvider from '../../short_link_provider';
+
+const fakeCancellationToken = new class implements vscode.CancellationToken {
+  isCancellationRequested!: boolean;
+  onCancellationRequested!: vscode.Event<any>;
+};
+
+// Create vscode.TextDocument from text and run ShortLinkProvider on it.
+async function getLinks(text: string) {
+  const document = await vscode.workspace.openTextDocument({'content': text});
+  const provider = new shortLinkProvider.ShortLinkProvider();
+  return provider.provideDocumentLinks(document, fakeCancellationToken);
+}
+
+suite('Short Link Provider Test Suite', () => {
+  test('One Buganizer link', async () => {
+    const links = await getLinks('Duplicate of b/123456.');
+    assert.ok(links);
+    assert.strictEqual(links.length, 1);
+    const link = links[0];
+    assert.deepStrictEqual(link.target, vscode.Uri.parse('http://b/123456'));
+    const expectedRange = new vscode.Range(
+        new vscode.Position(0, 13),
+        new vscode.Position(0, 21),
+    );
+    assert.deepStrictEqual(link.range, expectedRange);
+  });
+
+  test('Two links', async () => {
+    const links = await getLinks('We created b/123456 for the crash.\n' +
+      'Migrated from crbug/987654 because Monorail is deprecated.');
+
+    assert.ok(links);
+    assert.strictEqual(links.length, 2);
+    const [b, crbug] = links;
+
+    assert.deepStrictEqual(b.target, vscode.Uri.parse('http://b/123456'));
+    const expectedBRange = new vscode.Range(
+        new vscode.Position(0, 11),
+        new vscode.Position(0, 19),
+    );
+    assert.deepStrictEqual(b.range, expectedBRange);
+
+    assert.deepStrictEqual(
+        crbug.target, vscode.Uri.parse('http://crbug/987654'));
+    const expectedCrbugRange = new vscode.Range(
+        new vscode.Position(1, 14),
+        new vscode.Position(1, 26),
+    );
+    assert.deepStrictEqual(crbug.range, expectedCrbugRange);
+  });
+
+  test('Bug tracker with number', async () => {
+    const links = await getLinks('TODO(chromium:123313): see also b:6527146.');
+    assert.ok(links);
+    assert.strictEqual(links.length, 2);
+    const expectedLinks = [
+      new vscode.DocumentLink(
+          new vscode.Range(
+              new vscode.Position(0, 5),
+              new vscode.Position(0, 20)),
+          vscode.Uri.parse('http://crbug/123313'),
+      ),
+      new vscode.DocumentLink(
+          new vscode.Range(
+              new vscode.Position(0, 32),
+              new vscode.Position(0, 41)),
+          vscode.Uri.parse('http://b/6527146'),
+      ),
+    ];
+    assert.deepStrictEqual(links, expectedLinks);
+  });
+
+  test('Todo with ldap', async () => {
+    const links = await getLinks('// TODO(hiroshi): create a chat app.');
+    assert.ok(links);
+    assert.strictEqual(links.length, 1);
+    const expectedLinks = [
+      new vscode.DocumentLink(
+          new vscode.Range(
+              new vscode.Position(0, 8),
+              new vscode.Position(0, 15)),
+          vscode.Uri.parse('http://teams/hiroshi'),
+      ),
+    ];
+    assert.deepStrictEqual(links, expectedLinks);
+  });
+
+  test('crrev and crbug', async () => {
+    const links = await getLinks('TODO(crbug.com/123456) crrev/c/3406219\n' +
+         'crrev.com/c/3406220');
+    assert.ok(links);
+    assert.strictEqual(links.length, 3);
+    const expectedLinks = [
+      new vscode.DocumentLink(
+          new vscode.Range(
+              new vscode.Position(0, 5),
+              new vscode.Position(0, 21)),
+          vscode.Uri.parse('http://crbug.com/123456'),
+      ),
+      new vscode.DocumentLink(
+          new vscode.Range(
+              new vscode.Position(0, 23),
+              new vscode.Position(0, 38)),
+          vscode.Uri.parse('http://crrev/c/3406219'),
+      ),
+      new vscode.DocumentLink(
+          new vscode.Range(
+              new vscode.Position(1, 0),
+              new vscode.Position(1, 19)),
+          vscode.Uri.parse('http://crrev.com/c/3406220'),
+      ),
+    ];
+    assert.deepStrictEqual(links, expectedLinks);
+  });
+
+  test('Mixed link types', async () => {
+    // Test that we can extract links matching different regular expressions.
+    const links = await getLinks(
+        'Duplicate of b/123456.\n' +
+        'TODO(sundar): fight spam\n' +
+        'TODO(chromium:123456): some text');
+    assert.ok(links);
+    // Verify only the number of results. The order of links depends on
+    // the order in which the extractors are run, so verifying an array would
+    // make the test fragile.
+    assert.strictEqual(links.length, 3);
+  });
+
+  test('Negative examples', async () => {
+    // Note, that VS Code provides links for things starting with http[s],
+    // so we should ignore such links.
+    const links = await getLinks(
+        'Text http://www.bing.com/ more text\n' +
+        'TODO(http://b/123456)\n' +
+        'Text http://crrev/c/123456 more text\n' +
+        'Text http://crbug/123456 more text\n' +
+        'Text usb:1234556 more text\n' +
+        'Text 70:88:6b:92:34:70 more text');
+    assert.ok(links);
+    assert.deepStrictEqual(links, []);
+  });
+});
diff --git a/ide_tooling/cros-ide/src/test/runTest.ts b/ide_tooling/cros-ide/src/test/runTest.ts
new file mode 100644
index 0000000..62c1ec8
--- /dev/null
+++ b/ide_tooling/cros-ide/src/test/runTest.ts
@@ -0,0 +1,26 @@
+// Copyright 2022 The Chromium OS 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 * as path from 'path';
+
+import {runTests} from '@vscode/test-electron';
+
+async function main() {
+  try {
+    // The folder containing the Extension Manifest package.json
+    // Passed to `--extensionDevelopmentPath`
+    const extensionDevelopmentPath = path.resolve(__dirname, '../../');
+
+    // The path to test runner
+    // Passed to --extensionTestsPath
+    const extensionTestsPath = path.resolve(__dirname, './integration/index');
+
+    // Download VS Code, unzip it and run the integration test
+    await runTests({extensionDevelopmentPath, extensionTestsPath});
+  } catch (err) {
+    console.error('Failed to run tests');
+    process.exit(1);
+  }
+}
+
+main();
diff --git a/ide_tooling/cros-ide/src/test/testing.ts b/ide_tooling/cros-ide/src/test/testing.ts
new file mode 100644
index 0000000..0197073
--- /dev/null
+++ b/ide_tooling/cros-ide/src/test/testing.ts
@@ -0,0 +1,67 @@
+// Copyright 2022 The Chromium OS 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 * as fs from 'fs';
+import * as path from 'path';
+
+/** Returns fake stdout or undefined if args is not handled. */
+type Handler = (args: string[]) => Promise<string | undefined>;
+
+export function exactMatch(wantArgs: string[],
+    handle: () => Promise<string>): Handler {
+  return async args => {
+    if (wantArgs.length === args.length &&
+      wantArgs.every((x, i) => x === args[i])) {
+      return await handle();
+    }
+    return undefined;
+  };
+}
+
+export function prefixMatch(wantPrefix: string[],
+    handle: (restArgs: string[]) => Promise<string>): Handler {
+  return async args => {
+    if (wantPrefix.length <= args.length &&
+      wantPrefix.every((x, i) => x === args[i])) {
+      return await handle(args.slice(wantPrefix.length));
+    }
+    return undefined;
+  };
+}
+
+export function lazyHandler(f: () => Handler): Handler {
+  return async args => {
+    return f()(args);
+  };
+}
+
+export class FakeExec {
+  handlers: Map<string, Handler[]> = new Map();
+  on(name: string, handle: Handler): FakeExec {
+    if (!this.handlers.has(name)) {
+      this.handlers.set(name, []);
+    }
+    this.handlers.get(name)!.push(handle);
+    return this;
+  }
+  async exec(name: string, args: string[],
+      _log?: (line: string) => void,
+      _opt?: { logStdout?: boolean }): Promise<string> {
+    for (const handler of (this.handlers.get(name) || [])) {
+      const res = await handler(args);
+      if (res !== undefined) {
+        return res;
+      }
+    }
+    throw new Error(`${name} ${args.join(' ')}: not handled`);
+  }
+}
+
+export async function putFiles(dir: string, files: {[name: string]: string}) {
+  for (const [name, content] of Object.entries(files)) {
+    const filePath = path.join(dir, name);
+    await fs.promises.mkdir(path.dirname(filePath), {recursive: true});
+    await fs.promises.writeFile(path.join(dir, name), content);
+  }
+}
diff --git a/ide_tooling/cros-ide/src/test/unit/common_util.test.ts b/ide_tooling/cros-ide/src/test/unit/common_util.test.ts
new file mode 100644
index 0000000..bf59414
--- /dev/null
+++ b/ide_tooling/cros-ide/src/test/unit/common_util.test.ts
@@ -0,0 +1,132 @@
+// Copyright 2022 The Chromium OS 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 * as assert from 'assert';
+import * as commonUtil from '../../common/common_util';
+
+class BlockingPromise {
+  readonly promise: Promise<void>;
+  unblock: () => void;
+  private constructor(created: (p: BlockingPromise) => void) {
+    this.unblock = () => { }; // placeholder to satisfy type system.
+    this.promise = new Promise(resolve => {
+      this.unblock = resolve;
+      created(this);
+    });
+  }
+  static async new(): Promise<BlockingPromise> {
+    return new Promise(resolve => {
+      return new BlockingPromise(resolve);
+    });
+  }
+}
+
+suite('Job manager', () => {
+  test('Jobs are throttled', async () => {
+    const manager = new commonUtil.JobManager();
+
+    const guard = await BlockingPromise.new();
+
+    const p1 = manager.offer(async () => {
+      await guard.promise;
+      return true;
+    });
+
+    await new Promise(resolve => setTimeout(resolve, 0)); // tick to run p1
+
+    const p2 = manager.offer(async () => {
+      assert.fail('Intermediate job should not run');
+    });
+
+    let p3Run = false;
+    const p3 = manager.offer(async () => {
+      // The last-offered job should be queued.
+      p3Run = true;
+    });
+
+    // Cancelled job should return immediately.
+    assert.strictEqual(await p2, null);
+
+    assert.strictEqual(p3Run, false); // p3 should not run while p1 is running
+
+    guard.unblock();
+
+    assert.strictEqual(await p1, true);
+    await p3;
+
+    assert.strictEqual(p3Run, true);
+  });
+
+  test('Errors', async () => {
+    const manager = new commonUtil.JobManager();
+
+    const guard = await BlockingPromise.new();
+
+    const p1 = manager.offer(async () => {
+      await guard.promise;
+      throw new Error('p1');
+    });
+
+    await new Promise(resolve => setTimeout(resolve, 0));
+
+    const p2 = manager.offer(async () => {
+      assert.fail('Intermediate job should not run');
+    });
+    const p3 = manager.offer(async () => {
+      throw new Error('p3');
+    });
+
+    await p2;
+
+    guard.unblock();
+    await assert.rejects(p1);
+    await assert.rejects(p3);
+  });
+});
+
+suite('Logging exec', () => {
+  test('Stdout is returned and stderr is logged', async () => {
+    let logs = '';
+    const out = await commonUtil.exec('sh',
+        ['-c', 'echo foo; echo bar 1>&2'], log => {
+          logs += log;
+        });
+    assert.strictEqual(out, 'foo\n');
+    assert.strictEqual(logs, 'bar\n');
+  });
+
+  test('Stdout and stderr are mixed if flag is true', async () => {
+    let logs = '';
+    await commonUtil.exec('sh',
+        ['-c', 'echo foo; echo bar 1>&2'], log => {
+          logs += log;
+        }, {logStdout: true});
+    assert.strictEqual(logs.length, 'foo\nbar\n'.length);
+  });
+
+  test('Throw on non-zero exit code', async () => {
+    let logs = '';
+    const p = commonUtil.exec('sh',
+        ['-c', 'echo foo 1>&2; exit 1'], log => {
+          logs += log;
+        }, {logStdout: true});
+    await assert.rejects(p);
+    assert.strictEqual(logs, 'foo\n');
+  });
+
+  test('Newlines are appended to log', async () => {
+    let logs = '';
+    const out = await commonUtil.exec('sh',
+        ['-c', 'echo -n foo; echo -n bar 1>&2;'], log => {
+          logs += log;
+        }, {logStdout: true});
+    assert.strictEqual(out, 'foo');
+    assert.deepStrictEqual(logs.split('\n').sort(), ['', 'bar', 'foo']);
+  });
+
+  test('Throws error when the command fails', async () => {
+    const p = commonUtil.exec('does_not_exist', ['--version']);
+    await assert.rejects(p);
+  });
+});
diff --git a/ide_tooling/cros-ide/src/test/unit/cros.test.ts b/ide_tooling/cros-ide/src/test/unit/cros.test.ts
new file mode 100644
index 0000000..a332ddd
--- /dev/null
+++ b/ide_tooling/cros-ide/src/test/unit/cros.test.ts
@@ -0,0 +1,34 @@
+// Copyright 2022 The Chromium OS 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 * as assert from 'assert';
+import * as fs from 'fs';
+import * as path from 'path';
+import * as commonUtil from '../../common/common_util';
+import * as cros from '../../common/cros';
+import * as testing from '../testing';
+
+suite('Cros', () => {
+  test('Get worked on boards', async () => {
+    await commonUtil.withTempDir(async td => {
+      await testing.putFiles(td, {
+        '/build/amd64-generic/x': 'x',
+        '/build/betty-pi-arc/x': 'x',
+        '/build/bin/x': 'x',
+        '/build/coral/x': 'x',
+      });
+
+      await fs.promises.utimes(path.join(td, '/build/amd64-generic'),
+          2 /* timestamp */, 2);
+      await fs.promises.utimes(path.join(td, '/build/betty-pi-arc'), 1, 1);
+      await fs.promises.utimes(path.join(td, '/build/coral'), 3, 3);
+
+      assert.deepStrictEqual(await cros.getSetupBoards(td), [
+        'coral',
+        'amd64-generic',
+        'betty-pi-arc',
+      ]);
+    });
+  });
+});
diff --git a/ide_tooling/cros-ide/src/test/unit/fleet_devices_provider.test.ts b/ide_tooling/cros-ide/src/test/unit/fleet_devices_provider.test.ts
new file mode 100644
index 0000000..c7fb426
--- /dev/null
+++ b/ide_tooling/cros-ide/src/test/unit/fleet_devices_provider.test.ts
@@ -0,0 +1,26 @@
+// Copyright 2022 The Chromium OS 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 * as commonUtil from '../../common/common_util';
+import * as fleetProvider from '../../dut_management/services/fleet_devices_provider';
+import {exactMatch, FakeExec} from '../testing';
+
+suite('Fleet Devices Provider', () => {
+  test('No leases', async () => {
+    const fakeExec = new FakeExec().on(
+        'crosfleet',
+        exactMatch(['dut', 'leases', '-json'], async () => {
+          return '{}\n';
+        }));
+    const cleanUpExec = commonUtil.setExecForTesting(fakeExec.exec.bind(fakeExec));
+    try {
+      const provider = new fleetProvider.FleetDevicesProvider();
+      await provider.updateCache();
+    } finally {
+      cleanUpExec();
+    }
+  });
+
+  // TODO: also test with non-empty data
+});
diff --git a/ide_tooling/cros-ide/src/test/unit/install_script.test.ts b/ide_tooling/cros-ide/src/test/unit/install_script.test.ts
new file mode 100644
index 0000000..0dd130b
--- /dev/null
+++ b/ide_tooling/cros-ide/src/test/unit/install_script.test.ts
@@ -0,0 +1,299 @@
+// Copyright 2022 The Chromium OS 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 * as assert from 'assert';
+import * as fs from 'fs';
+import * as commonUtil from '../../common/common_util';
+import * as install from '../../tools/install';
+import {exactMatch, FakeExec, lazyHandler, prefixMatch} from '../testing';
+
+suite('Install script', () => {
+  test('Install', async () => {
+    let tempFile = '';
+    let installed = false;
+    const fake = new FakeExec().on('gsutil',
+        exactMatch(['ls', 'gs://chromeos-velocity/ide/cros-ide'],
+            async () => {
+              return `gs://chromeos-velocity/ide/cros-ide/cros-ide-0.0.1.vsix
+gs://chromeos-velocity/ide/cros-ide/cros-ide-0.0.2.vsix@253d24b6b54fa72d21f622b8f1bb6cc9b6f3d435
+`;
+            }),
+    ).on('gsutil',
+        prefixMatch(['cp',
+          'gs://chromeos-velocity/ide/cros-ide/cros-ide-0.0.2.vsix@' +
+          '253d24b6b54fa72d21f622b8f1bb6cc9b6f3d435'],
+        async args => {
+          tempFile = args[0];
+          return '';
+        }),
+    ).on('code', lazyHandler(() => exactMatch(['--install-extension', tempFile],
+        async () => {
+          installed = true;
+          return '';
+        })),
+    );
+
+    const revert = commonUtil.setExecForTesting(fake.exec.bind(fake));
+    try {
+      await install.install();
+      assert.deepStrictEqual(installed, true);
+      const name = tempFile.split('/').pop();
+      assert.deepStrictEqual(name, 'cros-ide-0.0.2.vsix');
+    } finally {
+      revert();
+    }
+  });
+
+  test('Install with version', async () => {
+    let tempFile = '';
+    let installed = false;
+    const fake = new FakeExec().on('gsutil',
+        exactMatch(['ls', 'gs://chromeos-velocity/ide/cros-ide'],
+            async () => {
+              return `gs://chromeos-velocity/ide/cros-ide/cros-ide-0.0.1.vsix
+gs://chromeos-velocity/ide/cros-ide/cros-ide-0.0.2.vsix@253d24b6b54fa72d21f622b8f1bb6cc9b6f3d435
+`;
+            }),
+    ).on('gsutil', prefixMatch(['cp', 'gs://chromeos-velocity/ide/cros-ide/cros-ide-0.0.1.vsix'],
+        async args => {
+          tempFile = args[0];
+          return '';
+        }),
+    ).on('code', lazyHandler(() => exactMatch(
+        ['--install-extension', tempFile, '--force'], async () => {
+          installed = true;
+          return '';
+        })),
+    );
+
+    const revert = commonUtil.setExecForTesting(fake.exec.bind(fake));
+    try {
+      await install.install({major: 0, minor: 0, patch: 1});
+      assert.deepStrictEqual(installed, true);
+      const name = tempFile.split('/').pop();
+      assert.deepStrictEqual(name, 'cros-ide-0.0.1.vsix');
+
+      await assert.rejects(install.install({major: 0, minor: 0, patch: 99}));
+    } finally {
+      revert();
+    }
+  });
+});
+
+suite('Build and publish', async () => {
+  interface TestCase {
+    name: string,
+    isDirty?: boolean,
+    headIsNotMerged?: boolean,
+    customDiffOutput?: string,
+    customFilename?: string,
+    wantReject?: boolean,
+    wantBuilt?: boolean,
+    wantUploaded?: boolean,
+  };
+  const testCases: TestCase[] = [{
+    name: 'Success',
+    wantBuilt: true,
+    wantUploaded: true,
+  }, {
+    name: 'Git status is dirty',
+    isDirty: true,
+    wantReject: true,
+  }, {
+    name: 'HEAD is not merged to cros/main',
+    headIsNotMerged: true,
+    wantReject: true,
+  }, {
+    name: 'package.json is not updated',
+    // eslint-disable-next-line max-len
+    customDiffOutput: '',
+    wantReject: true,
+  }, {
+    name: 'Version is not updated',
+    // eslint-disable-next-line max-len
+    customDiffOutput: `diff --git a/ide_tooling/cros-ide/package.json b/ide_tooling/cros-ide/package.json
+index 11eef9ccd..0ee259d51 100644
+--- a/ide_tooling/cros-ide/package.json
++++ b/ide_tooling/cros-ide/package.json
+@@ -115,7 +115,7 @@
+           "command": "cros-ide.codeSearchOpenCurrentFile"
+         },
+         {
+-          "command" : "cros-ide.codeSearchSearchForSelection"
++          "command": "cros-ide.codeSearchSearchForSelection"
+         }
+       ],
+       "view/title": [
+`,
+    wantReject: true,
+  }, {
+    name: 'Generated version is old',
+    customFilename: 'cros-ide-0.0.2.vsix',
+    wantReject: true,
+    wantBuilt: true,
+  }];
+  testCases.forEach((testCase) => {
+    test(testCase.name, async () => {
+      const gitHash = 'b9dfaf485e2caf5030199166469ce28e91680255';
+      const filename = testCase.customFilename || 'cros-ide-0.0.3.vsix';
+
+      let tempDir = '';
+      let built = false;
+      let uploaded = false;
+
+      const fake = new FakeExec().on('git', exactMatch(['status', '--short'],
+          async () => {
+            return testCase.isDirty ? ' M src/tools/install.ts\n' : '';
+          }),
+      ).on('git', exactMatch(['rev-parse', 'HEAD'], async () => {
+        return gitHash;
+      })).on('git', exactMatch(
+          ['merge-base', '--is-ancestor', 'HEAD', 'cros/main'], async () => {
+            if (testCase.headIsNotMerged) {
+              throw new Error(`Exit code: 1`);
+            }
+            return '';
+          }),
+      ).on('git', exactMatch(['diff', '-p', 'HEAD~', '--', '**package.json'],
+          async () => {
+            if (testCase.customDiffOutput !== undefined) {
+              return testCase.customDiffOutput;
+            }
+            // eslint-disable-next-line max-len
+            return `diff --git a/ide_tooling/cros-ide/package.json b/ide_tooling/cros-ide/package.json
+index ee8697e11..877d91ddd 100644
+--- a/ide_tooling/cros-ide/package.json
++++ b/ide_tooling/cros-ide/package.json
+@@ -2,7 +2,7 @@
+   "name": "cros-ide",
+   "displayName": "cros-ide",
+   "description": "Connect to Chrome OS DUTs over VNC",
+-  "version": "0.0.2",
++  "version": "0.0.3",
+   "publisher": "cros-velocity",
+   "repository": "https://chromium.googlesource.com/chromiumos/chromite/+/HEAD/ide_tooling",
+   "engines": {
+`;
+          }),
+      ).on('gsutil', exactMatch(['ls', 'gs://chromeos-velocity/ide/cros-ide'],
+          async () => {
+            return `gs://chromeos-velocity/ide/cros-ide/cros-ide-0.0.1.vsix
+gs://chromeos-velocity/ide/cros-ide/cros-ide-0.0.2.vsix@253d24b6b54fa72d21f622b8f1bb6cc9b6f3d435
+`;
+          },
+      )).on('npx', prefixMatch(['vsce@1.103.1', 'package', '-o'],
+          async args => {
+            tempDir = args[0];
+            await fs.promises.writeFile(`${tempDir}${filename}`, '<fake>');
+            built = true;
+            return '';
+          }),
+      ).on('gsutil', lazyHandler(() => exactMatch(
+          ['cp', `${tempDir}${filename}`,
+            `gs://chromeos-velocity/ide/cros-ide/${filename}@${gitHash}`],
+          async () => {
+            uploaded = true;
+            return '';
+          },
+      )));
+
+      const revert = commonUtil.setExecForTesting(fake.exec.bind(fake));
+      try {
+        const result = install.buildAndUpload();
+        if (testCase.wantReject) {
+          await assert.rejects(result);
+        } else {
+          await result;
+        }
+        assert.strictEqual(built, !!testCase.wantBuilt);
+        assert.strictEqual(uploaded, !!testCase.wantUploaded);
+        if (built) {
+          assert.strictEqual(fs.existsSync(tempDir), false);
+        }
+      } finally {
+        revert();
+      }
+    },
+    );
+  });
+
+  test('Dev install', async () => {
+    let tempDir = '';
+    let built = false;
+    let installed = false;
+    const fake = new FakeExec().on('npx',
+        prefixMatch(['vsce@1.103.1', 'package', '-o'], async args => {
+          tempDir = args[0];
+          built = true;
+          // As old as the latest version in GS.
+          await fs.promises.writeFile(
+              `${tempDir}cros-ide-0.0.2.vsix`, '<fake>');
+          return '';
+        }),
+    ).on('code', lazyHandler(() => exactMatch(
+        ['--install-extension', `${tempDir}cros-ide-0.0.2.vsix`], async () => {
+          installed = true;
+          return '';
+        }),
+    ));
+
+    const revert = commonUtil.setExecForTesting(fake.exec.bind(fake));
+    try {
+      await install.installDev();
+      assert.strictEqual(built, true);
+      assert.strictEqual(installed, true);
+    } finally {
+      revert();
+    }
+  });
+});
+
+suite('Parse args', () => {
+  test('Dev', () => {
+    assert.deepStrictEqual(
+        install.parseArgs(['--dev']),
+        {
+          dev: true,
+        },
+    );
+  });
+  test('Upload', () => {
+    assert.deepStrictEqual(
+        install.parseArgs(['--upload']),
+        {
+          upload: true,
+        },
+    );
+  });
+  test('Force version', () => {
+    assert.deepStrictEqual(
+        install.parseArgs(['ts-node', 'install.ts', '--force', '1.2.3']),
+        {
+          forceVersion: {
+            major: 1,
+            minor: 2,
+            patch: 3,
+          },
+        },
+    );
+  });
+  test('Help', () => {
+    assert.deepStrictEqual(
+        install.parseArgs(['--help']),
+        {
+          help: true,
+        },
+    );
+  });
+  test('Throw on invalid input', () => {
+    assert.throws(() => install.parseArgs(['--force']));
+    assert.throws(() => install.parseArgs(['--force', 'invalid']));
+    assert.throws(() => install.parseArgs(['--force', 'v1.2.3']));
+    assert.throws(() => install.parseArgs(['--force', '1.2']));
+    assert.throws(() => install.parseArgs(['--force', '1.2.3.4']));
+    assert.throws(() => install.parseArgs(['--dev', '--upload']));
+    assert.throws(() => install.parseArgs(['--upload', '--force', '1.2.3']));
+    assert.throws(() => install.parseArgs(['--unknownflag']));
+  });
+});
diff --git a/ide_tooling/cros-ide/src/tools/install.ts b/ide_tooling/cros-ide/src/tools/install.ts
new file mode 100644
index 0000000..18d44d7
--- /dev/null
+++ b/ide_tooling/cros-ide/src/tools/install.ts
@@ -0,0 +1,289 @@
+// Copyright 2022 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * Script to manage installation of the extension.
+ */
+
+import * as fs from 'fs';
+import * as path from 'path';
+import * as commonUtil from '../common/common_util';
+
+function assertInsideChroot() {
+  if (!commonUtil.isInsideChroot()) {
+    throw new Error('not inside chroot');
+  }
+}
+
+const GS_PREFIX = 'gs://chromeos-velocity/ide/cros-ide';
+
+async function execute(name: string, args: string[], showStdout?: boolean) {
+  return await commonUtil.exec(
+      name, args, log => process.stderr.write(log), {logStdout: showStdout});
+}
+
+/**
+ * Find specified archive, or the latest one if version is unspecified.
+ *
+ * @throws Error if specified version is not found.
+ */
+async function findArchive(version?: Version): Promise<Archive> {
+  // The result of `gsutil ls` is lexicographically sorted.
+  const stdout = await execute('gsutil', ['ls', GS_PREFIX]);
+  const archives = stdout.trim().split('\n').map(url => {
+    return Archive.parse(url);
+  });
+  archives.sort(Archive.compareFn);
+  if (!version) {
+    return archives.pop()!;
+  }
+  for (const archive of archives) {
+    if (compareVersion(archive.version, version) === 0) {
+      return archive;
+    }
+  }
+  throw new Error(`Version ${versionToString(version)} not found`);
+}
+
+// Assert the working directory is clean and get git commit hash.
+async function cleanCommitHash() {
+  if (await execute('git', ['status', '--short'])) {
+    throw new Error('dirty git status; run the command in clean environment');
+  }
+  // IDE_CROS_MAIN_FOR_TESTING substitutes cros/main for manual testing.
+  const crosMain = process.env.IDE_CROS_MAIN_FOR_TESTING || 'cros/main';
+  try {
+    // Assert HEAD is an ancestor of cros/main (i.e. the HEAD is an
+    // already-merged commit).
+    await execute('git', ['merge-base', '--is-ancestor', 'HEAD', crosMain]);
+  } catch (_e) {
+    throw new Error('HEAD should be an ancestor of cros/main');
+  }
+  // HEAD commit should update version in package.json .
+  const diff = await execute('git',
+      ['diff', '-p', 'HEAD~', '--', '**package.json']);
+  if (!/^\+\s*"version"\s*:/m.test(diff)) {
+    throw new Error('HEAD commit should update version in package.json');
+  }
+  return await execute('git', ['rev-parse', 'HEAD']);
+}
+
+class Archive {
+  readonly version: Version;
+  constructor(readonly name: string, readonly hash?: string) {
+    this.version = versionFromFilename(name);
+  }
+
+  url() {
+    let res = `${GS_PREFIX}/${this.name}`;
+    if (this.hash !== undefined) {
+      res = `${res}@${this.hash}`;
+    }
+    return res;
+  }
+
+  static parse(url: string) {
+    const base = path.basename(url);
+    const [name, hash] = base.split('@');
+    return new Archive(name, hash);
+  }
+
+  static compareFn(first: Archive, second: Archive): number {
+    return compareVersion(first.version, second.version);
+  }
+}
+
+export interface Version {
+  major: number
+  minor: number
+  patch: number
+}
+
+function compareVersion(first: Version, second: Version): number {
+  if (first.major !== second.major) {
+    return first.major - second.major;
+  }
+  if (first.minor !== second.minor) {
+    return first.minor - second.minor;
+  }
+  if (first.patch !== second.patch) {
+    return first.patch - second.patch;
+  }
+  return 0;
+}
+
+// Get version from filename such as "cros-ide-0.0.1.vsix"
+function versionFromFilename(name: string): Version {
+  const suffix = name.split('-').pop()!;
+  const version = suffix.split('.').slice(0, 3).join('.');
+  return versionFromString(version);
+}
+
+/**
+ * Get version from string such as "0.0.1".
+ * @throws Error on invalid input.
+ */
+function versionFromString(s: string): Version {
+  const version = s.trim().split('.').map(Number);
+  if (version.length !== 3 || version.some(isNaN)) {
+    throw new Error(`Invalid version format ${s}`);
+  }
+  return {
+    major: version[0],
+    minor: version[1],
+    patch: version[2],
+  };
+}
+
+function versionToString(v: Version): string {
+  return `${v.major}.${v.minor}.${v.patch}`;
+}
+
+async function build(tempDir: string, hash?: string): Promise<Archive> {
+  await execute('npx', ['vsce@1.103.1', 'package', '-o', `${tempDir}/`]);
+  const localName: string = (await fs.promises.readdir(tempDir))[0];
+  return new Archive(localName, hash);
+}
+
+export async function buildAndUpload() {
+  const latestInGs = await findArchive();
+  const hash = await cleanCommitHash();
+
+  await commonUtil.withTempDir(async td => {
+    const built = await build(td, hash);
+    if (compareVersion(latestInGs.version, built.version) >= 0) {
+      throw new Error(
+          `${built.name} is older than the latest published version ` +
+        `${latestInGs.name}. Update the version and rerun the program.`);
+    }
+    await execute('gsutil', ['cp', path.join(td, built.name), built.url()]);
+  });
+}
+
+export async function installDev() {
+  await commonUtil.withTempDir(async td => {
+    const built = await build(td);
+    const src = path.join(td, built.name);
+    await execute('code', ['--install-extension', src], true);
+  });
+}
+
+export async function install(forceVersion?: Version) {
+  const src = await findArchive(forceVersion);
+
+  await commonUtil.withTempDir(async td => {
+    const dst = path.join(td, src.name);
+
+    await execute('gsutil', ['cp', src.url(), dst]);
+    const args = ['--install-extension', dst];
+    if (forceVersion) {
+      args.push('--force');
+    }
+    await execute('code', args, true);
+  });
+}
+
+interface Config {
+  forceVersion?: Version
+  dev?: boolean
+  upload?: boolean
+  help?: boolean
+}
+
+/**
+ * Parse args.
+ *
+ * @throws Error on invalid input
+ */
+export function parseArgs(args: string[]): Config {
+  args = args.slice(); // not to modify the given parameter
+  while (args.length > 0 && !args[0].startsWith('--')) {
+    args.shift();
+  }
+
+  const config: Config = {};
+  while (args.length > 0) {
+    const flag = args.shift();
+    switch (flag) {
+      case '--dev':
+        config.dev = true;
+        break;
+      case '--upload':
+        config.upload = true;
+        break;
+      case '--force':
+        const s = args.shift();
+        if (!s) {
+          throw new Error('Version is not given; see --help');
+        }
+        config.forceVersion = versionFromString(s);
+        break;
+      case '--help':
+        config.help = true;
+        break;
+      default:
+        throw new Error(`Unknown flag ${flag}; see --help`);
+    }
+  }
+  if (config.dev && config.upload || config.dev && config.forceVersion ||
+    config.upload && config.forceVersion) {
+    throw new Error(`Invalid flag combination; see --help`);
+  }
+  return config;
+}
+
+const USAGE = `
+Usage:
+ install.sh [options]
+
+Basic options:
+
+ --force version
+    Force install specified version (example: --force 0.0.1)
+    Without this option, the latest version will be installed.
+
+ --help
+    Print this message
+
+Developer options:
+
+ --dev
+    Build the extension from the current source code and install it
+
+ --upload
+    Build and upload the extension
+`;
+
+async function main() {
+  const config = parseArgs(process.argv);
+  if (config.help) {
+    console.log(USAGE);
+    return;
+  }
+  if (config.upload) {
+    await buildAndUpload();
+    return;
+  }
+  if (config.dev) {
+    assertInsideChroot();
+    await installDev();
+    return;
+  }
+  try {
+    assertInsideChroot();
+    await install(config.forceVersion);
+  } catch (e) {
+    const message = (e as Error).message;
+    throw new Error(
+        `${message}\n` +
+      'Read quickstart.md and run the script in proper environment');
+  }
+}
+
+if (require.main === module) {
+  main().catch(e => {
+    console.error(e);
+    process.exit(1);
+  });
+}
diff --git a/ide_tooling/cros-ide/src/tools/preupload_hook.ts b/ide_tooling/cros-ide/src/tools/preupload_hook.ts
new file mode 100644
index 0000000..5cd4d06
--- /dev/null
+++ b/ide_tooling/cros-ide/src/tools/preupload_hook.ts
@@ -0,0 +1,38 @@
+// Copyright 2022 The Chromium OS 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 * as commonUtil from '../common/common_util';
+
+async function main(commitHash: string | undefined) {
+  if (!commitHash) {
+    throw Error('PRESUBMIT_COMMIT environment variable is not set');
+  }
+  const headHash = (await commonUtil.exec('git', ['rev-parse', 'HEAD'])).trim();
+  if (commitHash !== headHash) {
+    // We test only HEAD. If multiple commits are sent together we skip testing
+    // intermediate commits. This is not ideal, but for testing an intermediate
+    // commit, we need to checkout the commit, which pollutes user's git reflog.
+    return;
+  }
+  if (commonUtil.isInsideChroot()) {
+    throw new Error('Cannot test cros-ide inside chroot; please run repo ' +
+      'upload outside chroot');
+  }
+  if (await commonUtil.exec('git', ['status', '--short'])) {
+    throw new Error('Tests cannot run on dirty git status ' +
+      '(consider running git stash)');
+  }
+  if (!(await commonUtil.exec('node', ['--version'])).startsWith('v12.')) {
+    throw new Error('Node version should be v12.*');
+  }
+  await commonUtil.exec('npm', ['run', 'test'], console.error,
+      {logStdout: true});
+}
+
+if (require.main === module) {
+  main(process.env.PRESUBMIT_COMMIT).catch(e => {
+    console.error(e);
+    process.exit(1);
+  });
+}
diff --git a/ide_tooling/cros-ide/src/workon.ts b/ide_tooling/cros-ide/src/workon.ts
new file mode 100644
index 0000000..e5714e1
--- /dev/null
+++ b/ide_tooling/cros-ide/src/workon.ts
@@ -0,0 +1,55 @@
+// Copyright 2022 The Chromium OS 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 * as childProcess from 'child_process';
+import * as vscode from 'vscode';
+
+// Provides commands to run cros_workon start/stop from the IDE.
+export function activate(context: vscode.ExtensionContext) {
+  const startCmd = vscode.commands.registerCommand(
+      'cros-ide.crosWorkonStart',
+      crosWorkon('start'));
+
+  const stopCmd = vscode.commands.registerCommand(
+      'cros-ide.crosWorkonStop',
+      crosWorkon('stop'));
+
+  context.subscriptions.push(startCmd, stopCmd);
+}
+
+function crosWorkon(cmd: string) {
+  return async function crosWorkonStart(board?: string, pkg?: string) {
+    // When the command if called from the command pallete, board and pkg
+    // are not provided and we will prompt the user.
+
+    if (!board) {
+      board = await vscode.window.showInputBox({
+        title: 'Board',
+        placeHolder: 'board, e.g. betty',
+      });
+      if (!board) {
+        return;
+      }
+    }
+
+    if (!pkg) {
+      pkg = await vscode.window.showInputBox({
+        title: 'Package',
+        placeHolder: 'package, e.g. chromeos-base/shill',
+      });
+      if (!pkg) {
+        return;
+      }
+    }
+
+    // TODO: Should we refresh 'boards and packages' view?
+    childProcess.exec(
+        `cros workon --board=${board} ${cmd} ${pkg}`,
+        (error, stdout, stderr) => {
+          if (error) {
+            vscode.window.showInformationMessage(stderr);
+          }
+        },
+    );
+  };
+}
diff --git a/ide_tooling/cros-ide/tsconfig.json b/ide_tooling/cros-ide/tsconfig.json
new file mode 100644
index 0000000..9601959
--- /dev/null
+++ b/ide_tooling/cros-ide/tsconfig.json
@@ -0,0 +1,20 @@
+{
+  "compilerOptions": {
+    "module": "commonjs",
+    "target": "ES2020",
+    "lib": [
+      "ES2020"
+    ],
+    "sourceMap": true,
+    "rootDir": "src",
+    "strict": true   /* enable all strict type-checking options */
+    /* Additional Checks */
+    // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
+    // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
+    // "noUnusedParameters": true,  /* Report errors on unused parameters. */
+  },
+  "exclude": [
+    "node_modules",
+    ".vscode-test"
+  ]
+}
diff --git a/ide_tooling/cros-ide/webpack.config.js b/ide_tooling/cros-ide/webpack.config.js
new file mode 100644
index 0000000..2c64899
--- /dev/null
+++ b/ide_tooling/cros-ide/webpack.config.js
@@ -0,0 +1,58 @@
+// Copyright 2022 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//@ts-check
+
+'use strict';
+
+const path = require('path');
+
+//@ts-check
+/** @typedef {import('webpack').Configuration} WebpackConfig **/
+
+/** @type WebpackConfig */
+const extensionConfig = {
+  target: 'node', // vscode extensions run in a Node.js-context
+                  //-> https://webpack.js.org/configuration/node/
+  mode: 'none', // this leaves the source code as close as possible to the
+                //original (when packaging we set this to 'production')
+
+  entry: './src/extension.ts', // the entry point of this extension,
+                    //-> https://webpack.js.org/configuration/entry-context/
+  output: {
+    // the bundle is stored in the 'dist' folder (check package.json),
+    //-> https://webpack.js.org/configuration/output/
+    path: path.resolve(__dirname, 'dist'),
+    filename: 'extension.js',
+    libraryTarget: 'commonjs2'
+  },
+  externals: {
+    vscode: 'commonjs vscode' // the vscode-module is created on-the-fly
+    //and must be excluded. Add other modules that cannot be webpack'ed,
+    // -> https://webpack.js.org/configuration/externals/
+    // modules added here also need to be added in the .vscodeignore file
+  },
+  resolve: {
+    // support reading TypeScript and JavaScript files,
+    // -> https://github.com/TypeStrong/ts-loader
+    extensions: ['.ts', '.js']
+  },
+  module: {
+    rules: [
+      {
+        test: /\.ts$/,
+        exclude: /node_modules/,
+        use: [
+          {
+            loader: 'ts-loader'
+          }
+        ]
+      }
+    ]
+  },
+  devtool: 'nosources-source-map',
+  infrastructureLogging: {
+    level: "log", // enables logging required for problem matchers
+  },
+};
+module.exports = [ extensionConfig ];
diff --git a/ide_tooling/cros-sdk-proxy/README.md b/ide_tooling/cros-sdk-proxy/README.md
new file mode 100644
index 0000000..86af766
--- /dev/null
+++ b/ide_tooling/cros-sdk-proxy/README.md
@@ -0,0 +1,55 @@
+# VSCode extension prototype
+
+This repository contains prototype code for VSCode extensions for Chrome OS.
+
+## CrOS SDK Proxy
+
+CrOS SDK Proxy allows you to connect to CrOS chroot by SSH
+without exposing any network ports.
+
+### Installation
+
+Clone this repository to your development workstation, and run the following
+command.
+
+```shell
+# Binary goes to ~/go/bin/cros-sdk-proxy.
+go install ./cmd/cros-sdk-proxy
+```
+
+### Setting up SSH config for local access
+
+If you run the VSCode client on your development workstation, add the following
+entry to `~/.ssh/config`.
+
+```
+Host cros
+ProxyCommand ~/go/bin/cros-sdk-proxy enter --root=${CROS_ROOT}
+StrictHostKeyChecking no
+UserKnownHostsFile /dev/null
+```
+
+- `${CROS_ROOT}` is the path to the root directory of your CrOS source code
+  checkout.
+
+Then you can connect to chroot by `ssh cros`.
+
+### Setting up SSH config for remote access
+
+If you run the VSCode client on a remote client machine, add the following entry
+to `~/.ssh/config` **on the remote client machine** (not on the development
+workstation).
+
+```
+Host cros
+ProxyCommand ssh ${SSH_HOST} go/bin/cros-sdk-proxy enter --root=${CROS_ROOT}
+StrictHostKeyChecking no
+UserKnownHostsFile /dev/null
+```
+
+- `${SSH_HOST}` is the host name of the development workstation. Password-less
+  SSH access to the workstation should be configured in advance.
+- `${CROS_ROOT}` is the path to the root directory of your CrOS source code
+  checkout.
+
+Then you can connect to chroot by `ssh cros`.
diff --git a/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/logging/logging.go b/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/logging/logging.go
new file mode 100644
index 0000000..0a162f6
--- /dev/null
+++ b/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/logging/logging.go
@@ -0,0 +1,77 @@
+// Copyright 2021 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package logging
+
+import (
+	"fmt"
+	"log/syslog"
+	"os"
+	"path/filepath"
+	"time"
+)
+
+var syslogWriter = func() *syslog.Writer {
+	w, err := syslog.New(syslog.LOG_INFO, filepath.Base(os.Args[0]))
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "WARNING: syslog logging is unavailable: %v\n", err)
+		return nil
+	}
+	return w
+}()
+
+type Level int
+
+const (
+	LevelInfo Level = iota
+	LevelError
+)
+
+func (l Level) String() string {
+	switch l {
+	case LevelInfo:
+		return "INFO"
+	case LevelError:
+		return "ERROR"
+	default:
+		return "<unknown>"
+	}
+}
+
+func Info(args ...interface{}) {
+	Log(LevelInfo, args...)
+}
+
+func Infof(format string, args ...interface{}) {
+	Logf(LevelInfo, format, args...)
+}
+
+func Error(args ...interface{}) {
+	Log(LevelError, args...)
+}
+
+func Errorf(format string, args ...interface{}) {
+	Logf(LevelError, format, args...)
+}
+
+func Log(level Level, args ...interface{}) {
+	log(level, fmt.Sprint(args...))
+}
+
+func Logf(level Level, format string, args ...interface{}) {
+	log(level, fmt.Sprintf(format, args...))
+}
+
+func log(level Level, msg string) {
+	line := fmt.Sprintf("%s %s %s\n", time.Now().Format(time.RFC3339Nano), level, msg)
+	os.Stderr.WriteString(line)
+	if syslogWriter != nil {
+		switch level {
+		case LevelInfo:
+			syslogWriter.Info(msg)
+		case LevelError:
+			syslogWriter.Err(msg)
+		}
+	}
+}
diff --git a/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/subcommands/askpass/command.go b/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/subcommands/askpass/command.go
new file mode 100644
index 0000000..c5e86be
--- /dev/null
+++ b/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/subcommands/askpass/command.go
@@ -0,0 +1,47 @@
+// Copyright 2021 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package askpass
+
+import (
+	"io"
+	"io/ioutil"
+	"net"
+	"os"
+
+	"github.com/urfave/cli/v2"
+
+	"go.chromium.org/vscode/cmd/cros-sdk-proxy/internal/logging"
+)
+
+var FlagSocketPath = &cli.StringFlag{
+	Name:     "socket-path",
+	Required: true,
+	Usage:    "path to UNIX domain socket to connect to relay",
+}
+
+var Command = &cli.Command{
+	Name:   "askpass",
+	Hidden: true,
+	Flags: []cli.Flag{
+		FlagSocketPath,
+	},
+	Usage: "prompts sudo password via SSH keyboard-interactive auth",
+	Action: func(c *cli.Context) error {
+		socketPath := c.String(FlagSocketPath.Name)
+
+		logging.Info("Starting askpass")
+
+		logging.Infof("Connecting to %s", socketPath)
+		conn, err := net.DialUnix("unix", nil, &net.UnixAddr{Net: "unix", Name: socketPath})
+		if err != nil {
+			return err
+		}
+		defer conn.Close()
+
+		b, _ := ioutil.ReadAll(conn)
+		io.WriteString(os.Stdout, string(b))
+		return nil
+	},
+}
diff --git a/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/subcommands/daemon/command.go b/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/subcommands/daemon/command.go
new file mode 100644
index 0000000..4fd682f
--- /dev/null
+++ b/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/subcommands/daemon/command.go
@@ -0,0 +1,41 @@
+// Copyright 2021 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package daemon
+
+import (
+	"fmt"
+	"os"
+
+	"github.com/urfave/cli/v2"
+	"golang.org/x/crypto/ssh"
+
+	"go.chromium.org/vscode/cmd/cros-sdk-proxy/internal/logging"
+	"go.chromium.org/vscode/cmd/cros-sdk-proxy/internal/subcommands/daemon/daemonsshd"
+	"go.chromium.org/vscode/cmd/cros-sdk-proxy/internal/utils/pipe"
+	"go.chromium.org/vscode/cmd/cros-sdk-proxy/internal/utils/sshd"
+)
+
+var Command = &cli.Command{
+	Name:   "daemon",
+	Hidden: true,
+	Flags:  []cli.Flag{},
+	Usage:  "starts daemon in chroot",
+	Action: func(c *cli.Context) error {
+		logging.Info("Starting daemon (inside chroot)")
+
+		cfg := &ssh.ServerConfig{
+			NoClientAuth: true,
+		}
+		cfg.AddHostKey(sshd.MockSigner)
+		serverConn, newChans, globalReqs, err := ssh.NewServerConn(pipe.NewConn(os.Stdin, os.Stdout), cfg)
+		if err != nil {
+			return fmt.Errorf("external handshake failed: %w", err)
+		}
+		defer serverConn.Close()
+
+		daemonsshd.Run(serverConn, newChans, globalReqs)
+		return nil
+	},
+}
diff --git a/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/subcommands/daemon/daemonsshd/payload.go b/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/subcommands/daemon/daemonsshd/payload.go
new file mode 100644
index 0000000..db5e9d9
--- /dev/null
+++ b/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/subcommands/daemon/daemonsshd/payload.go
@@ -0,0 +1,69 @@
+// Copyright 2021 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package daemonsshd
+
+type envPayload struct {
+	VariableName  string
+	VariableValue string
+}
+
+type ptyRequestPayload struct {
+	TerminalName   string
+	WidthInChars   uint32
+	HeightInChars  uint32
+	WidthInPixels  uint32
+	HeightInPixels uint32
+	TerminalModes  string
+}
+
+type execPayload struct {
+	Command string
+}
+
+type windowChangePayload struct {
+	WidthInChars   uint32
+	HeightInChars  uint32
+	WidthInPixels  uint32
+	HeightInPixels uint32
+}
+
+type exitStatusPayload struct {
+	Code uint32
+}
+
+type exitSignalPayload struct {
+	SignalName   string
+	CoreDumped   bool
+	ErrorMessage string
+	LanguageTag  string
+}
+
+type directTCPIPPayload struct {
+	TargetHost     string
+	TargetPort     uint32
+	OriginatorHost string
+	OriginatorPort uint32
+}
+
+type tcpipForwardPayload struct {
+	BindAddress string
+	BindPort    uint32
+}
+
+type tcpipForwardSuccessPayload struct {
+	BindPort uint32
+}
+
+type cancelTCPIPForwardPayload struct {
+	BindAddress string
+	BindPort    uint32
+}
+
+type forwardedTCPIPPayload struct {
+	ConnectedHost  string
+	ConnectedPort  uint32
+	OriginatorHost string
+	OriginatorPort uint32
+}
diff --git a/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/subcommands/daemon/daemonsshd/sshd.go b/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/subcommands/daemon/daemonsshd/sshd.go
new file mode 100644
index 0000000..5e04795
--- /dev/null
+++ b/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/subcommands/daemon/daemonsshd/sshd.go
@@ -0,0 +1,386 @@
+// Copyright 2021 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package daemonsshd
+
+import (
+	"errors"
+	"fmt"
+	"io"
+	"net"
+	"os"
+	"os/exec"
+	"strconv"
+	"strings"
+	"sync"
+	"syscall"
+
+	"github.com/creack/pty"
+	"golang.org/x/crypto/ssh"
+	"golang.org/x/sys/unix"
+
+	"go.chromium.org/vscode/cmd/cros-sdk-proxy/internal/logging"
+)
+
+type forwardKey struct {
+	BindAddress string
+	BindPort    uint32
+}
+
+func Run(serverConn *ssh.ServerConn, newChans <-chan ssh.NewChannel, globalReqs <-chan *ssh.Request) {
+	var wg sync.WaitGroup
+	wg.Add(1)
+	go func() {
+		defer wg.Done()
+		for newChan := range newChans {
+			newChan := newChan
+			wg.Add(1)
+			go func() {
+				defer wg.Done()
+				handleNewChannel(newChan)
+			}()
+		}
+	}()
+
+	forwards := make(map[forwardKey]*net.TCPListener)
+	defer func() {
+		for _, listener := range forwards {
+			listener.Close()
+		}
+	}()
+
+	for globalReq := range globalReqs {
+		handleGlobalRequest(serverConn, globalReq, forwards)
+	}
+	wg.Wait()
+}
+
+func handleGlobalRequest(serverConn *ssh.ServerConn, req *ssh.Request, forwards map[forwardKey]*net.TCPListener) {
+	switch req.Type {
+	case "tcpip-forward":
+		var p tcpipForwardPayload
+		if err := ssh.Unmarshal(req.Payload, &p); err != nil {
+			req.Reply(false, nil)
+			return
+		}
+
+		// Only allow binding to localhost.
+		listener, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", uint16(p.BindPort)))
+		if err != nil {
+			req.Reply(false, nil)
+			return
+		}
+
+		// p.BindPort can be 0, in which case a random port is assigned.
+		port := uint32(listener.Addr().(*net.TCPAddr).Port)
+		key := forwardKey{
+			BindAddress: p.BindAddress,
+			BindPort:    port,
+		}
+		forwards[key] = listener.(*net.TCPListener)
+
+		go serveForwards(serverConn, listener.(*net.TCPListener))
+
+		req.Reply(true, ssh.Marshal(&tcpipForwardSuccessPayload{BindPort: port}))
+
+	case "cancel-tcpip-forward":
+		var p cancelTCPIPForwardPayload
+		if err := ssh.Unmarshal(req.Payload, &p); err != nil {
+			req.Reply(false, nil)
+			return
+		}
+		key := forwardKey{
+			BindAddress: p.BindAddress,
+			BindPort:    p.BindPort,
+		}
+		listener, ok := forwards[key]
+		if !ok {
+			req.Reply(false, nil)
+			return
+		}
+		listener.Close()
+		delete(forwards, key)
+		req.Reply(true, nil)
+
+	default:
+		req.Reply(false, nil)
+	}
+}
+
+func serveForwards(serverConn *ssh.ServerConn, listener *net.TCPListener) {
+	for {
+		conn, err := listener.AcceptTCP()
+		if err != nil {
+			return
+		}
+		go handleNewForward(serverConn, conn)
+	}
+}
+
+func handleNewForward(serverConn *ssh.ServerConn, conn *net.TCPConn) {
+	localAddr := conn.LocalAddr().(*net.TCPAddr)
+	remoteAddr := conn.RemoteAddr().(*net.TCPAddr)
+	ch, reqs, err := serverConn.OpenChannel("forwarded-tcpip", ssh.Marshal(&forwardedTCPIPPayload{
+		ConnectedHost:  "localhost", // localAddr.IP.String(),
+		ConnectedPort:  uint32(localAddr.Port),
+		OriginatorHost: remoteAddr.IP.String(),
+		OriginatorPort: uint32(remoteAddr.Port),
+	}))
+	if err != nil {
+		conn.Close()
+		return
+	}
+	serveForward(ch, reqs, conn)
+}
+
+func handleNewChannel(newChan ssh.NewChannel) {
+	switch newChan.ChannelType() {
+	case "session":
+		ch, reqs, err := newChan.Accept()
+		if err != nil {
+			return
+		}
+		serveSession(ch, reqs)
+	case "direct-tcpip":
+		var p directTCPIPPayload
+		if err := ssh.Unmarshal(newChan.ExtraData(), &p); err != nil {
+			newChan.Reject(ssh.Prohibited, fmt.Sprintf("corrupted direct-tcpip payload: %v", err))
+			return
+		}
+		conn, err := net.Dial("tcp", net.JoinHostPort(p.TargetHost, strconv.FormatUint(uint64(p.TargetPort), 10)))
+		if err != nil {
+			newChan.Reject(ssh.ConnectionFailed, fmt.Sprintf("direct-tcpip: %v", err))
+			return
+		}
+		ch, reqs, err := newChan.Accept()
+		if err != nil {
+			conn.Close()
+			return
+		}
+		serveForward(ch, reqs, conn.(*net.TCPConn))
+	default:
+		newChan.Reject(ssh.UnknownChannelType, fmt.Sprintf("unsupported channel type: %s", newChan.ChannelType()))
+	}
+}
+
+func serveForward(ch ssh.Channel, reqs <-chan *ssh.Request, conn *net.TCPConn) {
+	defer ch.Close()
+	defer conn.Close()
+
+	// Discard all requests on the forwarding channel.
+	go func() {
+		for range reqs {
+		}
+	}()
+
+	var wg sync.WaitGroup
+	wg.Add(2)
+	go func() {
+		defer wg.Done()
+		io.Copy(ch, conn)
+		ch.CloseWrite()
+	}()
+	go func() {
+		defer wg.Done()
+		io.Copy(conn, ch)
+		conn.CloseWrite()
+	}()
+	wg.Wait()
+}
+
+type windowSize struct {
+	Width, Height uint32
+}
+
+func serveSession(ch ssh.Channel, reqs <-chan *ssh.Request) {
+	defer ch.Close()
+
+	// procCh is initially nil. It is set to a valid channel when a process
+	// starts. The channel is closed when it finishes.
+	var procCh <-chan struct{}
+
+	var extraEnvs []string
+	wantPty := false
+	windowEvents := make(chan windowSize, 1)
+	defer close(windowEvents)
+	pushWindowEvent := func(ws windowSize) {
+		// Assumption: pushWindowEvent is the only sender of the channel.
+		select {
+		case windowEvents <- ws:
+		case <-windowEvents:
+			windowEvents <- ws
+		}
+	}
+
+	for {
+		select {
+		case <-procCh:
+			return
+		case req := <-reqs:
+			err := func() error {
+				switch req.Type {
+				case "pty-req":
+					var p ptyRequestPayload
+					if err := ssh.Unmarshal(req.Payload, &p); err != nil {
+						return err
+					}
+					if procCh != nil {
+						return errors.New("process already started")
+					}
+					wantPty = true
+					extraEnvs = append(extraEnvs, fmt.Sprintf("TERM=%s", p.TerminalName))
+					pushWindowEvent(windowSize{Width: p.WidthInChars, Height: p.HeightInChars})
+					return nil
+				case "env":
+					var p envPayload
+					if err := ssh.Unmarshal(req.Payload, &p); err != nil {
+						logging.Errorf("Failed to parse %s: %v", req.Type, err)
+						return err
+					}
+					if procCh != nil {
+						return errors.New("process already started")
+					}
+					extraEnvs = append(extraEnvs, fmt.Sprintf("%s=%s", p.VariableName, p.VariableValue))
+					return nil
+				case "shell":
+					if procCh != nil {
+						return errors.New("process already started")
+					}
+					var err error
+					procCh, err = runCommand("/bin/bash", []string{"-l"}, extraEnvs, ch, wantPty, windowEvents)
+					return err
+				case "exec":
+					var p execPayload
+					if err := ssh.Unmarshal(req.Payload, &p); err != nil {
+						return err
+					}
+					if procCh != nil {
+						return errors.New("process already started")
+					}
+					var err error
+					procCh, err = runCommand("/bin/bash", []string{"-c", p.Command}, extraEnvs, ch, wantPty, windowEvents)
+					return err
+				case "window-change":
+					var p windowChangePayload
+					if err := ssh.Unmarshal(req.Payload, &p); err != nil {
+						return err
+					}
+					if procCh == nil {
+						return errors.New("process not started")
+					}
+					pushWindowEvent(windowSize{Width: p.WidthInChars, Height: p.HeightInChars})
+					return nil
+				default:
+					return errors.New("unsupported request type")
+				}
+			}()
+			if err != nil {
+				logging.Errorf("Channel request %s rejected: %v", req.Type, err)
+				req.Reply(false, nil)
+			} else {
+				req.Reply(true, nil)
+			}
+		}
+	}
+}
+
+func runCommand(name string, args []string, extraEnvs []string, ch ssh.Channel, wantPty bool, windowEvents <-chan windowSize) (<-chan struct{}, error) {
+	var proc *exec.Cmd
+	var err error
+	if wantPty {
+		proc, err = startCommandWithPty(name, args, extraEnvs, ch, windowEvents)
+	} else {
+		proc, err = startCommandNoPty(name, args, extraEnvs, ch)
+	}
+	if err != nil {
+		return nil, err
+	}
+
+	procCh := make(chan struct{})
+	go func() {
+		defer close(procCh)
+
+		proc.Wait()
+		status := proc.ProcessState.Sys().(syscall.WaitStatus)
+		if status.Signaled() {
+			payload := ssh.Marshal(&exitSignalPayload{
+				SignalName:   strings.TrimPrefix(unix.SignalName(status.Signal()), "SIG"),
+				CoreDumped:   status.CoreDump(),
+				ErrorMessage: proc.ProcessState.String(),
+			})
+			ch.SendRequest("exit-signal", false, payload)
+		} else {
+			payload := ssh.Marshal(&exitStatusPayload{
+				Code: uint32(status.ExitStatus()),
+			})
+			ch.SendRequest("exit-status", false, payload)
+		}
+	}()
+
+	return procCh, nil
+}
+
+func startCommandWithPty(name string, args []string, extraEnvs []string, ch ssh.Channel, windowEvents <-chan windowSize) (*exec.Cmd, error) {
+	ptmx, tty, err := pty.Open()
+	if err != nil {
+		return nil, err
+	}
+
+	proc := exec.Command(name, args...)
+	proc.Env = append(os.Environ(), extraEnvs...)
+	proc.SysProcAttr = &syscall.SysProcAttr{
+		Setsid:  true,
+		Setctty: true,
+	}
+	proc.Stdin = tty
+	proc.Stdout = tty
+	proc.Stderr = tty
+
+	if err := proc.Start(); err != nil {
+		ptmx.Close()
+		return nil, err
+	}
+
+	// Relay stdio.
+	go io.Copy(ch, ptmx)
+	go io.Copy(ptmx, ch)
+
+	// Relay window events.
+	go func() {
+		// HACK: Close ptmx on the end of windowEvents, which indicates
+		// that the session finished.
+		defer ptmx.Close()
+
+		for ws := range windowEvents {
+			pty.Setsize(ptmx, &pty.Winsize{
+				Cols: uint16(ws.Width),
+				Rows: uint16(ws.Height),
+			})
+		}
+	}()
+	return proc, nil
+}
+
+func startCommandNoPty(name string, args []string, extraEnvs []string, ch ssh.Channel) (*exec.Cmd, error) {
+	proc := exec.Command(name, args...)
+	proc.Env = append(os.Environ(), extraEnvs...)
+	stdin, _ := proc.StdinPipe()
+	stdout, _ := proc.StdoutPipe()
+	proc.Stderr = ch.Stderr()
+	if err := proc.Start(); err != nil {
+		return nil, err
+	}
+
+	// Stdin needs special cares since channel input might not be closed.
+	go func() {
+		io.Copy(stdin, ch)
+		stdin.Close()
+	}()
+	// Stdout needs special cares to relay EOF.
+	go func() {
+		io.Copy(ch, stdout)
+		ch.CloseWrite()
+	}()
+	return proc, nil
+}
diff --git a/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/subcommands/enter/askpass.go b/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/subcommands/enter/askpass.go
new file mode 100644
index 0000000..7b38765
--- /dev/null
+++ b/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/subcommands/enter/askpass.go
@@ -0,0 +1,86 @@
+// Copyright 2021 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package enter
+
+import (
+	"fmt"
+	"net"
+	"os"
+	"path/filepath"
+
+	"github.com/alessio/shellescape"
+
+	"go.chromium.org/vscode/cmd/cros-sdk-proxy/internal/subcommands/askpass"
+)
+
+type askpassServer struct {
+	tempDir    string
+	clientPath string
+	listener   net.Listener
+}
+
+func newAskpassServer() (_ *askpassServer, retErr error) {
+	tempDir, err := os.MkdirTemp("", "cros-sdk-proxy.*")
+	if err != nil {
+		return nil, err
+	}
+	defer func() {
+		if retErr != nil {
+			os.RemoveAll(tempDir)
+		}
+	}()
+
+	socketPath := filepath.Join(tempDir, "askpass.socket")
+	listener, err := net.Listen("unix", socketPath)
+	if err != nil {
+		return nil, err
+	}
+	defer func() {
+		if retErr != nil {
+			listener.Close()
+		}
+	}()
+
+	exePath, err := os.Executable()
+	if err != nil {
+		return nil, err
+	}
+
+	clientPath := filepath.Join(tempDir, "askpass.sh")
+	clientCode := fmt.Sprintf(
+		"#!/bin/sh\nexec %s %s --%s=%s",
+		shellescape.Quote(exePath),
+		shellescape.Quote(askpass.Command.Name),
+		shellescape.Quote(askpass.FlagSocketPath.Name),
+		shellescape.Quote(socketPath))
+	if err := os.WriteFile(clientPath, []byte(clientCode), 0700); err != nil {
+		return nil, err
+	}
+
+	return &askpassServer{
+		tempDir:    tempDir,
+		clientPath: clientPath,
+		listener:   listener,
+	}, nil
+}
+
+func (s *askpassServer) Listener() net.Listener {
+	return s.listener
+}
+
+func (s *askpassServer) ClientPath() string {
+	return s.clientPath
+}
+
+func (s *askpassServer) Close() error {
+	var firstErr error
+	if err := s.listener.Close(); err != nil && firstErr == nil {
+		firstErr = err
+	}
+	if err := os.RemoveAll(s.tempDir); err != nil && firstErr == nil {
+		firstErr = err
+	}
+	return firstErr
+}
diff --git a/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/subcommands/enter/command.go b/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/subcommands/enter/command.go
new file mode 100644
index 0000000..a8b94d1
--- /dev/null
+++ b/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/subcommands/enter/command.go
@@ -0,0 +1,168 @@
+// Copyright 2021 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package enter
+
+import (
+	"fmt"
+	"io"
+	"os"
+	"os/exec"
+	"path/filepath"
+
+	"github.com/urfave/cli/v2"
+	"golang.org/x/crypto/ssh"
+	"golang.org/x/sys/unix"
+
+	"go.chromium.org/vscode/cmd/cros-sdk-proxy/internal/logging"
+	"go.chromium.org/vscode/cmd/cros-sdk-proxy/internal/subcommands/daemon"
+	"go.chromium.org/vscode/cmd/cros-sdk-proxy/internal/subcommands/enter/relaysshd"
+	"go.chromium.org/vscode/cmd/cros-sdk-proxy/internal/utils/pipe"
+	"go.chromium.org/vscode/cmd/cros-sdk-proxy/internal/utils/sshd"
+)
+
+var flagRootDir = &cli.StringFlag{
+	Name:     "root",
+	Required: true,
+	Usage:    "path to a Chrome OS source checkout",
+}
+
+var flagLoopback = &cli.BoolFlag{
+	Name:   "loopback",
+	Hidden: true,
+	Usage:  "executes a local shell instead of entering chroot (for testing only)",
+}
+
+var Command = &cli.Command{
+	Name: "enter",
+	Flags: []cli.Flag{
+		flagRootDir,
+		flagLoopback,
+	},
+	Usage: "enters chroot",
+	Action: func(c *cli.Context) error {
+		rootDir := c.String(flagRootDir.Name)
+		loopback := c.Bool(flagLoopback.Name)
+
+		logging.Info("Starting relay (outside chroot)")
+
+		askpass, err := newAskpassServer()
+		if err != nil {
+			return err
+		}
+		defer askpass.Close()
+
+		var proc *exec.Cmd
+		var procStdio *os.File
+		defer func() {
+			if proc == nil {
+				return
+			}
+			procStdio.Close()
+			proc.Process.Signal(unix.SIGTERM)
+			proc.Wait()
+		}()
+
+		serverConfig := &ssh.ServerConfig{
+			KeyboardInteractiveCallback: func(conn ssh.ConnMetadata, challenge ssh.KeyboardInteractiveChallenge) (*ssh.Permissions, error) {
+				// Open the self binary.
+				exePath, err := os.Executable()
+				if err != nil {
+					return nil, err
+				}
+
+				exeFile, err := os.Open(exePath)
+				if err != nil {
+					return nil, err
+				}
+				defer exeFile.Close()
+
+				// Create a socketpair for communication.
+				// SOCK_CLOEXEC is important to prevent child processes from
+				// inheriting sockets. See comments for syscall.ForkLock for
+				// details.
+				fds, err := unix.Socketpair(unix.AF_UNIX, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0)
+				if err != nil {
+					return nil, err
+				}
+				relaySocket := os.NewFile(uintptr(fds[0]), "")
+				daemonSocket := os.NewFile(uintptr(fds[1]), "")
+				defer func() {
+					if relaySocket != nil {
+						relaySocket.Close()
+					}
+				}()
+				defer daemonSocket.Close()
+
+				// Start cros_sdk.
+				args := []string{
+					"sudo", "--askpass",
+					"env", fmt.Sprintf("DEPOT_TOOLS=%s/src/chromium/depot_tools", rootDir),
+					filepath.Join(rootDir, "chromite/bin/cros_sdk")}
+				if loopback {
+					args = nil
+				}
+				args = append(args, "bash", "-c", `exec 3<&0 0<&1; exec -a "$0" /proc/self/fd/3 "$@"`, os.Args[0], daemon.Command.Name)
+				proc := exec.Command(args[0], args[1:]...)
+				proc.Env = append(os.Environ(), fmt.Sprintf("SUDO_ASKPASS=%s", askpass.ClientPath()))
+				proc.Stdin = exeFile       // stdin: self exe
+				proc.Stdout = daemonSocket // stdout: socket
+				proc.Stderr = os.Stderr    // stderr: pass through
+				if err := proc.Start(); err != nil {
+					return nil, err
+				}
+
+				// Close the daemon socket now so that we can read EOF from
+				// relaySocket when the subprocess exits.
+				daemonSocket.Close()
+
+				// Start the auth goroutine.
+				go func() {
+					for {
+						conn, err := askpass.Listener().Accept()
+						if err != nil {
+							logging.Infof("Auth goroutine exiting: %v", err)
+							break
+						}
+
+						answers, err := challenge("", "", []string{"sudo password to enter chroot: "}, []bool{false})
+						if err == nil && len(answers) == 1 {
+							io.WriteString(conn, answers[0])
+						}
+						conn.Close()
+					}
+				}()
+
+				// Wait until stdout becomes readable.
+				unix.Poll([]unix.PollFd{{Fd: int32(relaySocket.Fd()), Events: unix.POLLIN}}, -1)
+
+				// Unblock the auth goroutine.
+				askpass.Listener().Close()
+
+				procStdio = relaySocket
+				relaySocket = nil
+				return nil, nil
+			},
+		}
+		serverConfig.AddHostKey(sshd.MockSigner)
+
+		server, serverNewChans, serverGlobalReqs, err := ssh.NewServerConn(pipe.NewConn(os.Stdin, os.Stdout), serverConfig)
+		if err != nil {
+			return fmt.Errorf("SSH relay handshake failed: %w", err)
+		}
+		defer server.Close()
+
+		clientConfig := &ssh.ClientConfig{
+			HostKeyCallback: ssh.InsecureIgnoreHostKey(),
+		}
+		client, clientNewChans, clientGlobalReqs, err := ssh.NewClientConn(pipe.NewConn(procStdio, procStdio), "", clientConfig)
+		if err != nil {
+			return fmt.Errorf("SSH daemon handshake failed: %w", err)
+		}
+		defer client.Close()
+
+		relaysshd.Run(server, serverNewChans, serverGlobalReqs, client, clientNewChans, clientGlobalReqs)
+		return nil
+	},
+}
diff --git a/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/subcommands/enter/relaysshd/sshd.go b/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/subcommands/enter/relaysshd/sshd.go
new file mode 100644
index 0000000..b39c5f6
--- /dev/null
+++ b/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/subcommands/enter/relaysshd/sshd.go
@@ -0,0 +1,136 @@
+// Copyright 2021 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package relaysshd
+
+import (
+	"io"
+	"sync"
+
+	"golang.org/x/crypto/ssh"
+)
+
+func Run(server *ssh.ServerConn, serverNewChans <-chan ssh.NewChannel, serverGlobalReqs <-chan *ssh.Request, client ssh.Conn, clientNewChans <-chan ssh.NewChannel, clientGlobalReqs <-chan *ssh.Request) {
+	var wg sync.WaitGroup
+	wg.Add(4)
+
+	go func() {
+		defer wg.Done()
+		relayNewChannels(client, serverNewChans)
+	}()
+	go func() {
+		defer wg.Done()
+		relayNewChannels(server, clientNewChans)
+	}()
+	go func() {
+		defer wg.Done()
+		relayGlobalRequests(client, serverGlobalReqs)
+	}()
+	go func() {
+		defer wg.Done()
+		relayGlobalRequests(server, clientGlobalReqs)
+	}()
+
+	wg.Wait()
+}
+
+func relayGlobalRequests(dstConn ssh.Conn, srcReqs <-chan *ssh.Request) {
+	for srcReq := range srcReqs {
+		ok, payload, err := dstConn.SendRequest(srcReq.Type, srcReq.WantReply, srcReq.Payload)
+		if err != nil {
+			return
+		}
+		srcReq.Reply(ok, payload)
+	}
+}
+
+func relayNewChannels(dstConn ssh.Conn, srcNewChans <-chan ssh.NewChannel) {
+	var wg sync.WaitGroup
+	for newChan := range srcNewChans {
+		newChan := newChan
+		wg.Add(1)
+		go func() {
+			defer wg.Done()
+			handleNewChannel(dstConn, newChan)
+		}()
+	}
+	wg.Wait()
+}
+
+func handleNewChannel(dstConn ssh.Conn, newChan ssh.NewChannel) {
+	dstChan, dstChanReqs, err := dstConn.OpenChannel(newChan.ChannelType(), newChan.ExtraData())
+	if err != nil {
+		if err, ok := err.(*ssh.OpenChannelError); ok {
+			newChan.Reject(err.Reason, err.Message)
+		} else {
+			newChan.Reject(ssh.Prohibited, err.Error())
+		}
+		return
+	}
+
+	srcChan, srcChanReqs, err := newChan.Accept()
+	if err != nil {
+		return
+	}
+
+	var wg sync.WaitGroup
+	wg.Add(2)
+	go func() {
+		defer wg.Done()
+		relayChannel(dstChan, srcChan, srcChanReqs)
+	}()
+	go func() {
+		defer wg.Done()
+		relayChannel(srcChan, dstChan, dstChanReqs)
+	}()
+	wg.Wait()
+}
+
+func relayChannel(dstChan, srcChan ssh.Channel, srcReqs <-chan *ssh.Request) {
+	defer dstChan.Close()
+
+	var wg sync.WaitGroup
+	wg.Add(2)
+
+	go func() {
+		defer wg.Done()
+		relayChannelData(dstChan, srcChan)
+	}()
+	go func() {
+		defer wg.Done()
+		relayChannelRequests(dstChan, srcReqs)
+	}()
+
+	wg.Wait()
+}
+
+func relayChannelData(dstChan, srcChan ssh.Channel) {
+	var wg sync.WaitGroup
+	wg.Add(2)
+
+	// Relay stdout.
+	go func() {
+		defer wg.Done()
+		io.Copy(dstChan, srcChan)
+		dstChan.CloseWrite()
+	}()
+
+	// Relay stderr.
+	go func() {
+		defer wg.Done()
+		io.Copy(dstChan.Stderr(), srcChan.Stderr())
+	}()
+
+	wg.Wait()
+}
+
+func relayChannelRequests(dstChan ssh.Channel, srcReqs <-chan *ssh.Request) {
+	for req := range srcReqs {
+		ok, err := dstChan.SendRequest(req.Type, req.WantReply, req.Payload)
+		if err != nil {
+			return
+		}
+		req.Reply(ok, nil)
+	}
+}
diff --git a/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/utils/pipe/pipe.go b/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/utils/pipe/pipe.go
new file mode 100644
index 0000000..4afd01d
--- /dev/null
+++ b/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/utils/pipe/pipe.go
@@ -0,0 +1,72 @@
+// Copyright 2021 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package pipe
+
+import (
+	"errors"
+	"io"
+	"net"
+	"time"
+)
+
+var (
+	// fakeAddr is a fake IPv4 address.
+	fakeAddr = &net.IPAddr{IP: net.IPv4zero}
+
+	// errNotImpl is returned from unimplemented methods in Conn.
+	errNotImpl = errors.New("not implemented")
+)
+
+// Conn is a pseudo net.Conn implementation based on io.Reader and io.Writer.
+type Conn struct {
+	r io.Reader
+	w io.Writer
+}
+
+func NewConn(r io.Reader, w io.Writer) *Conn {
+	return &Conn{r: r, w: w}
+}
+
+// Read reads data from the underlying io.Reader.
+func (c *Conn) Read(b []byte) (n int, err error) {
+	return c.r.Read(b)
+}
+
+// Write writes data to the underlying io.Writer.
+func (c *Conn) Write(b []byte) (n int, err error) {
+	return c.w.Write(b)
+}
+
+// Close does nothing.
+func (c *Conn) Close() error {
+	return nil
+}
+
+// LocalAddr returns a fake IPv4 address.
+func (c *Conn) LocalAddr() net.Addr {
+	return fakeAddr
+}
+
+// RemoteAddr returns a fake IPv4 address.
+func (c *Conn) RemoteAddr() net.Addr {
+	return fakeAddr
+}
+
+// SetDeadline always returns not implemented error.
+func (c *Conn) SetDeadline(t time.Time) error {
+	return errNotImpl
+}
+
+// SetReadDeadline always returns not implemented error.
+func (c *Conn) SetReadDeadline(t time.Time) error {
+	return errNotImpl
+}
+
+// SetWriteDeadline always returns not implemented error.
+func (c *Conn) SetWriteDeadline(t time.Time) error {
+	return errNotImpl
+}
+
+var _ net.Conn = &Conn{}
diff --git a/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/utils/sshd/sshd.go b/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/utils/sshd/sshd.go
new file mode 100644
index 0000000..97ba9d8
--- /dev/null
+++ b/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/internal/utils/sshd/sshd.go
@@ -0,0 +1,21 @@
+// Copyright 2021 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package sshd
+
+import (
+	"golang.org/x/crypto/ssh"
+)
+
+// MockSigner is a Signer with a fixed private key.
+var MockSigner, _ = ssh.ParsePrivateKey([]byte(
+	`-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
+QyNTUxOQAAACCFFcEwNvRhAnwGgyyr8BJzApEC1MaZIWoJp9rQosIecAAAALBLnGo3S5xq
+NwAAAAtzc2gtZWQyNTUxOQAAACCFFcEwNvRhAnwGgyyr8BJzApEC1MaZIWoJp9rQosIecA
+AAAEBwX8Fk7FGl/3alxILUGYRnYSPIv3AX+25DknNCVfwRboUVwTA29GECfAaDLKvwEnMC
+kQLUxpkhagmn2tCiwh5wAAAAJ255YUBueWEtbWFjYm9va3Byby5yb2FtLmNvcnAuZ29vZ2
+xlLmNvbQECAwQFBg==
+-----END OPENSSH PRIVATE KEY-----
+`))
diff --git a/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/main.go b/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/main.go
new file mode 100644
index 0000000..9d6c539
--- /dev/null
+++ b/ide_tooling/cros-sdk-proxy/cmd/cros-sdk-proxy/main.go
@@ -0,0 +1,33 @@
+// Copyright 2021 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package main
+
+import (
+	"os"
+
+	"github.com/urfave/cli/v2"
+
+	"go.chromium.org/vscode/cmd/cros-sdk-proxy/internal/logging"
+	"go.chromium.org/vscode/cmd/cros-sdk-proxy/internal/subcommands/askpass"
+	"go.chromium.org/vscode/cmd/cros-sdk-proxy/internal/subcommands/daemon"
+	"go.chromium.org/vscode/cmd/cros-sdk-proxy/internal/subcommands/enter"
+)
+
+var app = &cli.App{
+	Name: "cros-sdk-proxy",
+	Commands: []*cli.Command{
+		enter.Command,
+		daemon.Command,
+		askpass.Command,
+	},
+	Usage: "provides SSH access to CrOS chroot",
+}
+
+func main() {
+	if err := app.Run(os.Args); err != nil {
+		logging.Error(err)
+		os.Exit(1)
+	}
+}
diff --git a/ide_tooling/cros-sdk-proxy/go.mod b/ide_tooling/cros-sdk-proxy/go.mod
new file mode 100644
index 0000000..0c85d2d
--- /dev/null
+++ b/ide_tooling/cros-sdk-proxy/go.mod
@@ -0,0 +1,11 @@
+module go.chromium.org/vscode
+
+go 1.16
+
+require (
+	github.com/alessio/shellescape v1.4.1
+	github.com/creack/pty v1.1.17
+	github.com/urfave/cli/v2 v2.3.0
+	golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e
+	golang.org/x/sys v0.0.0-20210909193231-528a39cd75f3
+)
diff --git a/ide_tooling/cros-sdk-proxy/go.sum b/ide_tooling/cros-sdk-proxy/go.sum
new file mode 100644
index 0000000..cef8eb1
--- /dev/null
+++ b/ide_tooling/cros-sdk-proxy/go.sum
@@ -0,0 +1,28 @@
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0=
+github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30=
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI=
+github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
+github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
+golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI=
+golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210909193231-528a39cd75f3 h1:3Ad41xy2WCESpufXwgs7NpDSu+vjxqLt2UFqUV+20bI=
+golang.org/x/sys v0.0.0-20210909193231-528a39cd75f3/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/ide_tooling/docs/quickstart.md b/ide_tooling/docs/quickstart.md
new file mode 100644
index 0000000..5ae7307
--- /dev/null
+++ b/ide_tooling/docs/quickstart.md
@@ -0,0 +1,49 @@
+# Modern IDE quickstart (go/cros-ide-quickstart)
+
+## Prerequisites
+
+Follow the [Chromium OS Developer Guide] and set up development environment.
+Especially [entering the chroot via cros_sdk] must be possible.
+
+[Chromium OS Developer Guide]: https://chromium.googlesource.com/chromiumos/docs/+/HEAD/developer_guide.md#chromium-os-developer-guide
+[entering the chroot via cros_sdk]: https://chromium.googlesource.com/chromiumos/docs/+/HEAD/developer_guide.md#Enter-the-chroot
+
+## Installation
+
+Complete the following process, and you get the modern IDE!
+
+### 1. Install VSCode
+
+Follow the internal guide of [installing VSCode](https://g3doc.corp.google.com/devtools/editors/vscode/g3doc/install.md?cl=head).
+
+### 2. Install cros-sdk-proxy
+
+Follow [../cros-sdk-proxy/README.md](../cros-sdk-proxy/README.md).
+
+  TODO(oka): Automate installation of the proxy.
+
+### 3. Connect to chroot via VSCode
+
+Install [Remote development] extension on the VSCode.
+Select SSH target `cros` and open your working directory under
+`/home/$USER/chromiumos/`.
+
+[Remote development]: https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack
+
+### 4. Install the extension
+
+Open terminal in the VSCode connected to `cros`, and run
+
+```
+~/chromiumos/chromite/ide_tooling/cros-ide/install.sh
+```
+
+To force-install old version of extension (say 0.0.1), run
+
+```
+~/chromiumos/chromite/ide_tooling/cros-ide/install.sh --force 0.0.1
+```
+
+  TODO(oka): Publish the extension to official marketplace to ease installation.
+
+### 5. That's it!
diff --git a/lib/OWNERS b/lib/OWNERS
index 33c1077..8e4dec6 100644
--- a/lib/OWNERS
+++ b/lib/OWNERS
@@ -8,6 +8,7 @@
 per-file device*=file:/OWNERS.chrome
 per-file dev_server*=file:/OWNERS.au
 per-file dlc*=file:/OWNERS.au
+per-file minios*=file:/OWNERS.au
 per-file nebraska*=file:/OWNERS.au
 per-file toolchain_util*=file:chromiumos/third_party/toolchain-utils:/OWNERS.toolchain
 per-file vm*=file:/OWNERS.chrome
diff --git a/lib/build_target_lib.py b/lib/build_target_lib.py
index 4220b54..ff5faf5 100644
--- a/lib/build_target_lib.py
+++ b/lib/build_target_lib.py
@@ -15,15 +15,11 @@
   """Base module error class."""
 
 
-class InvalidNameError(Error):
-  """Error for invalid target name argument."""
-
-
 class BuildTarget(object):
   """Class to handle the build target information."""
 
   def __init__(self,
-               name: str,
+               name: Optional[str],
                profile: Optional[str] = None,
                build_root: Optional[str] = None):
     """Build Target init.
@@ -33,11 +29,7 @@
       profile: The profile name.
       build_root: The path to the buildroot.
     """
-    if not name:
-      raise InvalidNameError('Name is required.')
-
-    self._name = name
-    self.board, _, self.variant = name.partition('_')
+    self._name = name or None
     self.profile = profile
 
     if build_root:
@@ -64,7 +56,7 @@
 
   @property
   def as_protobuf(self):
-    return common_pb2.BuildTarget(name=self.name)
+    return common_pb2.BuildTarget(name=self.name or '')
 
   @classmethod
   def from_protobuf(cls, message):
@@ -93,8 +85,15 @@
     Returns:
       The build target's command wrapper.
     """
+    if self.is_host():
+      return base_command
+
     return '%s-%s' % (base_command, self.name)
 
+  def is_host(self) -> bool:
+    """Check if the build target refers to the host."""
+    return not self.name
+
 
 def get_default_sysroot_path(build_target_name=None):
   """Get the default sysroot location or '/' if |build_target_name| is None."""
diff --git a/lib/build_target_lib_unittest.py b/lib/build_target_lib_unittest.py
index 149fd56..6d65213 100644
--- a/lib/build_target_lib_unittest.py
+++ b/lib/build_target_lib_unittest.py
@@ -8,7 +8,6 @@
 
 from chromite.api.gen.chromiumos import common_pb2
 from chromite.lib.build_target_lib import BuildTarget
-from chromite.lib.build_target_lib import InvalidNameError
 from chromite.lib import cros_test_lib
 from chromite.lib import osutils
 
@@ -32,15 +31,16 @@
     self.assertNotEqual(bt1, bt3)
     self.assertNotEqual(bt1, bt4)
 
-  def testInvalidName(self):
-    """Test invalid name check."""
-    with self.assertRaises(InvalidNameError):
-      BuildTarget('')
+  def testHostTarget(self):
+    """Test host target with empty name."""
+    target = BuildTarget('')
+    self.assertTrue(target.is_host())
 
   def testNormalRoot(self):
     """Test normalized sysroot path."""
     target = BuildTarget('board', build_root=self.sysroot)
     self.assertEqual(self.sysroot, target.root)
+    self.assertFalse(target.is_host())
 
   def testDenormalizedRoot(self):
     """Test a non-normal sysroot path."""
diff --git a/lib/buildbucket_v2.py b/lib/buildbucket_v2.py
index b15dc43..77469b9 100644
--- a/lib/buildbucket_v2.py
+++ b/lib/buildbucket_v2.py
@@ -397,7 +397,7 @@
   # I don't think there can ever be more than one entry in the list, but
   # could be zero.
   bot_id = GetStringPairValue(build, ['infra', 'swarming', 'botDimensions'],
-                             'id')
+                              'id')
   if not bot_id:
     return None
 
@@ -447,19 +447,19 @@
       if isinstance(buildbucket_id, str):
         buildbucket_id = int(buildbucket_id)
       batch_requests.append(
-        builds_service_pb2.BatchRequest.Request(
-          cancel_build=(
-            builds_service_pb2.CancelBuildRequest(
-              id=buildbucket_id,
-              summary_markdown=summary_markdown,
-              fields=(field_mask_pb2.FieldMask(paths=[properties])
-                      if properties else None)
-            )
+          builds_service_pb2.BatchRequest.Request(
+              cancel_build=(
+                  builds_service_pb2.CancelBuildRequest(
+                      id=buildbucket_id,
+                      summary_markdown=summary_markdown,
+                      fields=(field_mask_pb2.FieldMask(paths=[properties])
+                              if properties else None)
+                  )
+              )
           )
-        )
       )
     return self.client.Batch(builds_service_pb2.BatchRequest(
-      requests=batch_requests), **self._client_kwargs)
+        requests=batch_requests), **self._client_kwargs)
 
   # TODO(crbug/1006818): Need to handle ResponseNotReady given by luci prpc.
   @retry_util.WithRetry(max_retry=5, sleep=20.0, exception=SSLError)
@@ -480,19 +480,25 @@
     batch_requests = []
     for buildbucket_id in buildbucket_ids:
       batch_requests.append(
-        builds_service_pb2.BatchRequest.Request(
-          get_build=(
-            builds_service_pb2.GetBuildRequest(
-              id=buildbucket_id,
-              fields=(field_mask_pb2.FieldMask(paths=[properties])
-                      if properties else None)
-            )
+          builds_service_pb2.BatchRequest.Request(
+              get_build=(
+                  builds_service_pb2.GetBuildRequest(
+                      id=buildbucket_id,
+                      fields=(field_mask_pb2.FieldMask(paths=[properties])
+                              if properties else None)
+                  )
+              )
           )
-        )
       )
     return self.client.Batch(builds_service_pb2.BatchRequest(
-      requests=batch_requests), **self._client_kwargs)
+        requests=batch_requests), **self._client_kwargs)
 
+  # TODO(crbug/1006818): Need to handle ResponseNotReady given by luci prpc.
+  @retry_util.WithRetry(max_retry=5, sleep=60.0, exception=SSLError)
+  @retry_util.WithRetry(max_retry=5, sleep=60.0, exception=socket.error)
+  @retry_util.WithRetry(max_retry=5, sleep=60.0, exception=socket.timeout)
+  @retry_util.WithRetry(max_retry=5, sleep=60.0,
+                        exception=http.client.ResponseNotReady)
   def BatchSearchBuilds(self, search_requests):
     """SearchBuild RPC call wrapping function.
 
@@ -506,10 +512,10 @@
     requests = []
     for request in search_requests:
       requests.append(
-        builds_service_pb2.BatchRequest.Request(search_builds=request)
+          builds_service_pb2.BatchRequest.Request(search_builds=request)
       )
     return self.client.Batch(builds_service_pb2.BatchRequest(
-      requests=requests), **self._client_kwargs)
+        requests=requests), **self._client_kwargs)
 
   # TODO(crbug/1006818): Need to handle ResponseNotReady given by luci prpc.
   @retry_util.WithRetry(max_retry=5, sleep=20.0, exception=SSLError)
@@ -529,10 +535,10 @@
       https://chromium.googlesource.com/infra/luci/luci-go/+/HEAD/buildbucket/proto/build.proto
     """
     cancel_build_request = builds_service_pb2.CancelBuildRequest(
-         id=buildbucket_id,
-         summary_markdown=summary_markdown,
-         fields=(field_mask_pb2.FieldMask(paths=[properties])
-                 if properties else None)
+        id=buildbucket_id,
+        summary_markdown=summary_markdown,
+        fields=(field_mask_pb2.FieldMask(paths=[properties])
+                if properties else None)
     )
     return self.client.CancelBuild(cancel_build_request, **self._client_kwargs)
 
diff --git a/lib/cgroups.py b/lib/cgroups.py
index a58f5a4..5f34d03 100644
--- a/lib/cgroups.py
+++ b/lib/cgroups.py
@@ -696,7 +696,7 @@
     return _cros_node.AddGroup(target, autoclean=False)
 
 
-class ContainChildren(cros_build_lib.MasterPidContextManager):
+class ContainChildren(cros_build_lib.PrimaryPidContextManager):
   """Context manager for containing children processes.
 
   This manager creates a job pool derived from the specified Cgroup |node|
diff --git a/lib/chrome_committer.py b/lib/chrome_committer.py
deleted file mode 100644
index 01fceb9..0000000
--- a/lib/chrome_committer.py
+++ /dev/null
@@ -1,145 +0,0 @@
-# Copyright 2018 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Commits files to the chromium git repository."""
-
-import logging
-import os
-
-from chromite.lib import commandline
-from chromite.lib import constants
-from chromite.lib import cros_build_lib
-from chromite.lib import git
-from chromite.lib import osutils
-
-
-class CommitError(Exception):
-  """Raised if the commit failed."""
-
-
-class ChromeCommitter(object):
-  """Committer object responsible for committing a git change."""
-
-  def __init__(self, user_email, workdir, dryrun=False, cq=False):
-    logging.info('user_email=%s, checkout_dir=%s', user_email, workdir)
-    self.author = user_email
-    self._checkout_dir = workdir
-    self._git_committer_args = ['-c', 'user.email=%s' % user_email,
-                                '-c', 'user.name=%s' % user_email]
-    self._commit_msg = ''
-    self._dryrun = dryrun
-    self._cq = cq
-    assert not (dryrun and cq), "Can't CQ+1 and CQ+2 simultaneously."
-
-  def __del__(self):
-    self.Cleanup()
-
-  def FullPath(self, file_path):
-    """Returns the full path in the source tree given a relative path.
-
-    Args:
-      file_path: Path of file.
-
-    Returns:
-      Full path rooted in source checkout.
-    """
-    if os.path.isabs(file_path):
-      return file_path
-    return os.path.join(self._checkout_dir, file_path)
-
-  def Checkout(self, sparse_checkout):
-    """Checks out chrome into tmp checkout dir.
-
-    Args:
-      sparse_checkout: List of file paths to fetch.
-    """
-    assert isinstance(sparse_checkout, list)
-    sparse_checkout += ['codereview.settings', 'WATCHLISTS']
-    git.ShallowFetch(self._checkout_dir, constants.CHROMIUM_GOB_URL,
-                     sparse_checkout=sparse_checkout)
-    git.CreateBranch(self._checkout_dir, 'auto-commit-branch',
-                     branch_point='origin/master')
-
-  def Commit(self, file_paths, commit_msg):
-    """Commits files listed in |file_paths|.
-
-    Args:
-      file_paths: List of files to commit.
-      commit_msg: Message to use in commit.
-    """
-    assert file_paths and isinstance(file_paths, list)
-    # Make paths absolute and ensure they exist.
-    for i, file_path in enumerate(file_paths):
-      if not os.path.isabs(file_path):
-        file_paths[i] = self.FullPath(file_path)
-      if not os.path.exists(file_paths[i]):
-        raise CommitError('Invalid path: %s' % file_paths[i])
-
-    self._commit_msg = 'Automated Commit: ' + commit_msg
-    try:
-      for file_path in file_paths:
-        git.AddPath(file_path)
-      commit_args = ['commit', '-m', self._commit_msg]
-      git.RunGit(self._checkout_dir, self._git_committer_args + commit_args,
-                 print_cmd=True, stderr=True, capture_output=False)
-    except cros_build_lib.RunCommandError as e:
-      raise CommitError('Could not create git commit: %r' % e)
-
-  def Upload(self):
-    """Uploads the change to gerrit."""
-    logging.info('Uploading commit.')
-
-    try:
-      # Run 'git cl upload' with --bypass-hooks to skip running scripts that are
-      # not part of the shallow checkout, -f to skip editing the CL message,
-      upload_args = self._git_committer_args + [
-          'cl', 'upload', '-v', '-m', self._commit_msg, '--bypass-hooks', '-f',
-          '--reviewers', constants.CHROME_GARDENER_REVIEW_EMAIL,
-          '--set-bot-commit']
-      # Marks CL as ready.
-      upload_args += ['--send-mail']
-      if self._cq:
-        upload_args += ['--use-commit-queue']
-      elif self._dryrun:
-        upload_args += ['--dry-run']
-      git.RunGit(self._checkout_dir, upload_args, print_cmd=True,
-                 stderr=True, capture_output=False)
-    except cros_build_lib.RunCommandError as e:
-      # Log the change for debugging.
-      git.RunGit(self._checkout_dir, ['--no-pager', 'log', '--pretty=full'],
-                 capture_output=False)
-      raise CommitError('Could not submit: %r' % e)
-
-    logging.info('Submitted to CQ.')
-
-  def Cleanup(self):
-    """Remove chrome checkout."""
-    osutils.RmDir(self._checkout_dir, ignore_missing=True)
-
-  @staticmethod
-  def GetParser():
-    """Returns parser for ChromeCommitter.
-
-    Returns:
-      Parser for ChromeCommitter.
-    """
-    # We need to use the account used by the builder to upload git CLs when
-    # generating CLs.
-    default_git_account = None
-    if cros_build_lib.HostIsCIBuilder(golo_only=True):
-      default_git_account = 'chromeos-commit-bot@chromium.org'
-    elif cros_build_lib.HostIsCIBuilder(gce_only=True):
-      default_git_account = '3su6n15k.default@developer.gserviceaccount.com'
-
-    parser = commandline.ArgumentParser(usage=__doc__, add_help=False)
-    parser.add_argument('--dryrun', action='store_true', default=False,
-                        help="Don't commit changes or send out emails.")
-    parser.add_argument('--user_email', required=False,
-                        default=default_git_account,
-                        help='Email address to use when comitting changes.')
-    parser.add_argument('--workdir',
-                        default=os.path.join(os.getcwd(), 'chrome_src'),
-                        help=('Path to a checkout of the chrome src. '
-                              'Defaults to PWD/chrome_src'))
-    return parser
diff --git a/lib/chrome_committer_unittest.py b/lib/chrome_committer_unittest.py
deleted file mode 100644
index 8fb9c33..0000000
--- a/lib/chrome_committer_unittest.py
+++ /dev/null
@@ -1,111 +0,0 @@
-# Copyright 2018 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Unit tests for the chrome_committer library."""
-
-import os
-
-from chromite.lib import cros_test_lib
-from chromite.lib import osutils
-from chromite.lib import chrome_committer
-
-
-class ChromeCommitterTester(cros_test_lib.RunCommandTestCase,
-                            cros_test_lib.MockTempDirTestCase):
-  """Test cros_chromeos_lkgm.Committer."""
-
-  def setUp(self):
-    """Common set up method for all tests."""
-    osutils.SafeMakedirs(os.path.join(self.tempdir, '.git', 'info'))
-    osutils.WriteFile(os.path.join(self.tempdir, 'OWNERS'), 'foo@chromium.org')
-    osutils.SafeMakedirs(os.path.join(self.tempdir, 'chromeos'))
-    osutils.WriteFile(os.path.join(self.tempdir, 'chromeos', 'BUILD.gn'),
-                      'assert(is_chromeos)')
-    self.committer = chrome_committer.ChromeCommitter(
-        'user@test.org', self.tempdir)
-
-  def _assertCommand(self, git_cmd):
-    self.assertCommandContains(git_cmd.split(' '))
-
-  def testCheckout(self):
-    """Tests checkout with mocked out git."""
-    self.committer.Checkout(['OWNERS'])
-
-    self._assertCommand('git init')
-    self._assertCommand('git remote add origin '
-                        'https://chromium.googlesource.com/chromium/src.git')
-    self._assertCommand('git config core.sparsecheckout true')
-    self._assertCommand('git fetch --depth=1')
-    self._assertCommand('git pull origin master')
-    self._assertCommand('git checkout -B auto-commit-branch origin/master')
-    self.assertEqual(
-        osutils.ReadFile(os.path.join(self.tempdir, '.git', 'info',
-                                      'sparse-checkout')),
-        'OWNERS\ncodereview.settings\nWATCHLISTS')
-
-  def testCommit(self):
-    """Tests that we can commit a file."""
-    self.committer.Checkout(['OWNERS'])
-    self.committer.Commit(['OWNERS', 'chromeos/BUILD.gn'],
-                          'Modify OWNERS and BUILD.gn')
-
-    self._assertCommand('git add -- OWNERS')
-    self._assertCommand('git add -- BUILD.gn')
-    self.assertCommandContains(['git',
-                                '-c', 'user.email=user@test.org',
-                                '-c', 'user.name=user@test.org',
-                                'commit', '-m',
-                                'Automated Commit: Modify OWNERS and BUILD.gn'])
-
-    # Non-existent file should raise.
-    self.assertRaisesRegex(chrome_committer.CommitError,
-                           'Invalid path: /tmp/chromite.*/nonexistent$',
-                           self.committer.Commit,
-                           ['nonexistent'], 'Commit non-existent file')
-
-  def testUpload(self):
-    """Tests that we can upload a commit."""
-    self.committer.Checkout(['OWNERS'])
-    self.committer.Commit(['OWNERS', 'chromeos/BUILD.gn'],
-                          'Modify OWNERS and BUILD.gn')
-
-    self.committer.Upload()
-
-    self.assertCommandContains(['git',
-                                '-c', 'user.email=user@test.org',
-                                '-c', 'user.name=user@test.org',
-                                'cl', 'upload', '-v', '-m',
-                                'Automated Commit: Modify OWNERS and BUILD.gn',
-                                '--bypass-hooks', '-f',
-                                '--reviewers',
-                                'chrome-os-gardeners-reviews@google.com',
-                                '--set-bot-commit',
-                                '--send-mail'])
-
-  def testUploadCQ(self):
-    """Tests that we can upload a commit and submit it to the CQ."""
-    self.committer.Checkout(['OWNERS'])
-    self.committer.Commit(['OWNERS', 'chromeos/BUILD.gn'],
-                          'Modify OWNERS and BUILD.gn')
-
-    self.committer._cq = True  # pylint: disable=protected-access
-    self.committer.Upload()
-
-    self.assertCommandContains(['--use-commit-queue'])
-
-  def testUploadDryRun(self):
-    """Tests that we can upload a commit with dryrun."""
-    self.committer.Checkout(['OWNERS'])
-    self.committer.Commit(['OWNERS', 'chromeos/BUILD.gn'],
-                          'Modify OWNERS and BUILD.gn')
-
-    self.committer._dryrun = True  # pylint: disable=protected-access
-    self.committer.Upload()
-
-    self.assertCommandContains(['git',
-                                '-c', 'user.email=user@test.org',
-                                '-c', 'user.name=user@test.org',
-                                'cl', 'upload', '-v', '-m',
-                                'Automated Commit: Modify OWNERS and BUILD.gn',
-                                '--bypass-hooks', '-f', '--dry-run'])
diff --git a/lib/chrome_util.py b/lib/chrome_util.py
index fa8cf5a..0480d94 100644
--- a/lib/chrome_util.py
+++ b/lib/chrome_util.py
@@ -330,9 +330,10 @@
     # Copying icudtl.dat has to be optional because in CROS, icudtl.dat will
     # be installed by the package "chrome-icu", and icudtl.dat in chrome is
     # deleted in the chromeos-chrome ebuild. But we can not delete this line
-    # totally because chromite/deloy_chrome is used outside of ebuild
+    # totally because chromite/deploy_chrome is used outside of ebuild
     # (see https://crbug.com/1081884).
     Path('icudtl.dat', optional=True),
+    Path('icudtl.dat.hash', optional=True),
     Path('libosmesa.so', exe=True, optional=True),
     # Do not strip the nacl_helper_bootstrap binary because the binutils
     # objcopy/strip mangles the ELF program headers.
@@ -374,8 +375,13 @@
     Path('dbus/', optional=True),
     Path('keyboard_resources.pak'),
     Path('libassistant.so', exe=True, optional=True),
-    Path('libondeviceassistant.so', exe=True, optional=True),
     Path('libmojo_core.so', exe=True),
+    Path('libondeviceassistant.so', exe=True, optional=True),
+    Path(
+        'liboptimization_guide_internal.so',
+        exe=True,
+        cond=C.GnSetTo(_IS_CHROME_BRANDED, True),
+        optional=True),
     Path('libEGL.so', exe=True, optional=True),
     Path('libGLESv2.so', exe=True, optional=True),
 
@@ -387,12 +393,16 @@
     # Widevine CDM is already pre-stripped.  In addition, it doesn't
     # play well with the binutils stripping tools, so skip stripping.
     # Optional for arm64 builds (http://crbug.com/881022)
+    # TODO(crbug.com/971433): Once Chrome has been updated to use
+    # WidevineCdm/, remove reference to 'libwidevinecdm.so'.
     Path(
         'libwidevinecdm.so',
         exe=True,
         strip=False,
         cond=C.GnSetTo(_IS_CHROME_BRANDED, True),
-        optional=C.GnSetTo('target_cpu', 'arm64')),
+        optional=True),
+    Path('WidevineCdm/', optional=True),
+
     # In component build, copy so files (e.g. libbase.so) except for the
     # blacklist.
     Path(
@@ -414,6 +424,11 @@
     Path('resources.pak'),
     # TODO(crbug.com/1182258): remove once swiftshader is handled as DLC.
     Path('swiftshader/*.so', dest='swiftshader/', optional=True),
+    # Text file containing a seed for the chrome_variations_tast_tests target.
+    # This is not a chrome build artifact, just some variable test data that
+    # will be used by a Tast test that is too large to pass on the command
+    # line from a swarming task.
+    Path('variations_seed.txt', optional=True),
     Path('xdg-settings'),
     Path('*.png'),
 ) + _COPY_PATHS_COMMON
@@ -443,11 +458,14 @@
     Path('locales/', optional=True),
     Path('*.pak', optional=True),
     Path('icudtl.dat', optional=True),
+    Path('icudtl.dat.hash', optional=True),
     Path('snapshot_blob.bin', optional=True),
     Path('swiftshader/', optional=True),
     Path('crashpad_handler', exe=True, optional=True),
     Path('chrome_crashpad_handler', exe=True, optional=True),
     Path('WidevineCdm/', optional=True),
+    Path('libEGL.so', exe=True, optional=True),
+    Path('libGLESv2.so', exe=True, optional=True),
 )
 
 
diff --git a/lib/chromite_config.py b/lib/chromite_config.py
index c0eda10..1d56e06 100644
--- a/lib/chromite_config.py
+++ b/lib/chromite_config.py
@@ -7,7 +7,16 @@
 from pathlib import Path
 
 
-DIR = Path('~/.config/chromite').expanduser()
+# Respect the various XDG settings if the xdg module is available.  Otherwise
+# be lazy and hardcode the most common answer.
+try:
+  import xdg.BaseDirectory
+  XDG_CONFIG_HOME = Path(xdg.BaseDirectory.xdg_config_home)
+except ImportError:
+  XDG_CONFIG_HOME = Path('~/.config').expanduser()
+
+
+DIR = XDG_CONFIG_HOME / 'chromite'
 
 # List of configs that we might use.  Normally this would be declared in the
 # respective modules that actually use the config file, but having the list be
diff --git a/lib/chroot_lib.py b/lib/chroot_lib.py
index bd234fd..7b8a12f 100644
--- a/lib/chroot_lib.py
+++ b/lib/chroot_lib.py
@@ -30,12 +30,14 @@
                cache_dir=None,
                chrome_root=None,
                env=None,
-               goma=None):
+               goma=None,
+               remoteexec=None):
     # Strip trailing / if present for consistency.
     self._path = (path or constants.DEFAULT_CHROOT_PATH).rstrip('/')
     self._is_default_path = not bool(path)
     self._env = env
     self.goma = goma
+    self.remoteexec = remoteexec
     # String in proto are '' when not set, but testing and comparing is much
     # easier when the "unset" value is consistent, so do an explicit "or None".
     self.cache_dir = cache_dir or None
@@ -100,6 +102,11 @@
           '--goma_dir', self.goma.linux_goma_dir,
           '--goma_client_json', self.goma.goma_client_json,
       ])
+    if self.remoteexec:
+      args.extend([
+          '--reclient-dir', self.remoteexec.reclient_dir,
+          '--reproxy-cfg-file', self.remoteexec.reproxy_cfg_file,
+      ])
 
     return args
 
@@ -108,5 +115,7 @@
     env = self._env.copy() if self._env else {}
     if self.goma:
       env.update(self.goma.GetChrootExtraEnv())
+    if self.remoteexec:
+      env.update(self.remoteexec.GetChrootExtraEnv())
 
     return env
diff --git a/lib/chroot_lib_unittest.py b/lib/chroot_lib_unittest.py
index 3595985..41db326 100644
--- a/lib/chroot_lib_unittest.py
+++ b/lib/chroot_lib_unittest.py
@@ -9,6 +9,7 @@
 from chromite.lib import chroot_lib
 from chromite.lib import cros_test_lib
 from chromite.lib import osutils
+from chromite.lib import remoteexec_util
 
 
 class ChrootTest(cros_test_lib.TempDirTestCase):
@@ -26,8 +27,21 @@
     chrome_root = '/chrome/root'
     expected = ['--chroot', path, '--cache-dir', cache_dir,
                 '--chrome-root', chrome_root]
+
+    reclient_dir = os.path.join(self.tempdir, 'cipd/rbe')
+    osutils.SafeMakedirs(reclient_dir)
+    reproxy_cfg_file = os.path.join(self.tempdir,
+                                    'reclient_cfgs/reproxy_config.cfg')
+    osutils.Touch(reproxy_cfg_file, makedirs=True)
+    remoteexec = remoteexec_util.Remoteexec(
+        reclient_dir=reclient_dir,
+        reproxy_cfg_file=reproxy_cfg_file)
+    expected.extend(['--reproxy-cfg-file', reclient_dir,
+                     '--reclient-dir', reproxy_cfg_file])
+
     chroot = chroot_lib.Chroot(path=path, cache_dir=cache_dir,
-                               chrome_root=chrome_root)
+                               chrome_root=chrome_root,
+                               remoteexec=remoteexec)
 
     self.assertCountEqual(expected, chroot.get_enter_args())
 
@@ -37,6 +51,20 @@
     chroot = chroot_lib.Chroot(env=env)
     self.assertEqual(env, chroot.env)
 
+  def testEnvRemoteexec(self):
+    reclient_dir = os.path.join(self.tempdir, 'cipd/rbe')
+    osutils.SafeMakedirs(reclient_dir)
+    reproxy_cfg_file = os.path.join(self.tempdir,
+                                    'reclient_cfgs/reproxy_config.cfg')
+    osutils.SafeMakedirs(reproxy_cfg_file)
+    remoteexec = remoteexec_util.Remoteexec(
+        reclient_dir=reclient_dir,
+        reproxy_cfg_file=reproxy_cfg_file)
+
+    chroot = chroot_lib.Chroot(remoteexec=remoteexec)
+    self.assertEndsWith(chroot.env['RECLIENT_DIR'], '/reclient')
+    self.assertEndsWith(chroot.env['REPROXY_CFG'], '/reproxy_chroot.cfg')
+
   def testTempdir(self):
     """Test the tempdir functionality."""
     chroot = chroot_lib.Chroot(path=self.tempdir)
diff --git a/lib/chroot_util.py b/lib/chroot_util.py
index a0b8aa6..a46a519 100644
--- a/lib/chroot_util.py
+++ b/lib/chroot_util.py
@@ -153,8 +153,8 @@
   cros_build_lib.run(cmd)
 
 
-def RunUnittests(sysroot, packages, extra_env=None, verbose=False,
-                 retries=None, jobs=None):
+def RunUnittests(sysroot, packages, extra_env=None, keep_going=False,
+                 verbose=False, retries=None, jobs=None):
   """Runs the unit tests for |packages|.
 
   Args:
@@ -162,6 +162,7 @@
     packages: List of packages to test.
     extra_env: Python dictionary containing the extra environment variable to
       pass to the build command.
+    keep_going: Tolerent package failure from parallel_emerge.
     verbose: If True, show the output from emerge, even when the tests succeed.
     retries: Number of time we should retry a failed packages. If None, use
       parallel_emerge's default.
@@ -178,6 +179,10 @@
 
   command = [os.path.join(constants.CHROMITE_BIN_DIR, 'parallel_emerge'),
              '--sysroot=%s' % sysroot]
+
+  if keep_going:
+    command += ['--keep-going=y']
+
   if verbose:
     command += ['--show-output']
 
diff --git a/lib/chroot_util_unittest.py b/lib/chroot_util_unittest.py
index a772724..d08d2d7 100644
--- a/lib/chroot_util_unittest.py
+++ b/lib/chroot_util_unittest.py
@@ -12,6 +12,7 @@
 from chromite.lib import osutils
 from chromite.lib import path_util
 
+
 pytestmark = cros_test_lib.pytestmark_inside_only
 
 if cros_build_lib.IsInsideChroot():
@@ -88,3 +89,28 @@
       self.assertStartsWith(tempdir, chroot_tempdir)
     self.assertNotExists(rm_check_dir)
     osutils.RmDir(chroot_tempdir)
+
+  def testRunUnittests(self):
+    """Tests running unit tests invoking emerge with provided flags"""
+
+    sudo_run_mock = self.PatchObject(cros_build_lib, 'sudo_run')
+    chroot_util.RunUnittests(
+        sysroot='/sysroot/',
+        packages=['package1', 'package2'],
+        extra_env={'USE': 'chrome_internal coverage'},
+        keep_going=True
+    )
+    sudo_run_mock.assert_called_once_with(
+        [
+            '/mnt/host/source/chromite/bin/parallel_emerge',
+            '--sysroot=/sysroot/',
+            '--keep-going=y',
+            'package1',
+            'package2'
+        ],
+        extra_env={
+            'USE': 'chrome_internal coverage',
+            'FEATURES': 'test',
+            'PKGDIR': '/sysroot/test-packages'
+        }
+    )
diff --git a/lib/cipd.py b/lib/cipd.py
index a5f95a5..3a7bd0c 100644
--- a/lib/cipd.py
+++ b/lib/cipd.py
@@ -28,7 +28,7 @@
 # pylint: disable=line-too-long
 # CIPD client to download.
 #
-# This is version "git_revision:db7a486094873e3944b8e27ab5b23a3ae3c401e7".
+# This is version "git_revision:78137bc2d58ebea680b6d513a3d7f6a8d25aa643".
 #
 # To switch to another version:
 #   1. Find it in CIPD Web UI, e.g.
@@ -37,7 +37,7 @@
 # pylint: enable=line-too-long
 CIPD_CLIENT_PACKAGE = 'infra/tools/cipd/linux-amd64'
 CIPD_CLIENT_SHA256 = (
-    'ea6b7547ddd316f32fd9974f598949c3f8f22f6beb8c260370242d0d84825162')
+    'b431c29c9fa132d4f7d6e86f053af02d490b51d742b4f01ea55618a5365d357d')
 
 CHROME_INFRA_PACKAGES_API_BASE = (
     'https://chrome-infra-packages.appspot.com/prpc/cipd.Repository/')
diff --git a/lib/cleanup.py b/lib/cleanup.py
index 9a0a46e..7111bef 100644
--- a/lib/cleanup.py
+++ b/lib/cleanup.py
@@ -14,7 +14,7 @@
 from chromite.lib import locking
 
 
-class EnforcedCleanupSection(cros_build_lib.MasterPidContextManager):
+class EnforcedCleanupSection(cros_build_lib.PrimaryPidContextManager):
 
   """Context manager used to ensure that a section of cleanup code is run
 
@@ -40,7 +40,7 @@
   >>>
   """
   def __init__(self):
-    cros_build_lib.MasterPidContextManager.__init__(self)
+    cros_build_lib.PrimaryPidContextManager.__init__(self)
     self._lock = locking.ProcessLock(verbose=False)
     self._forked = False
     self._is_child = False
@@ -99,7 +99,7 @@
 
     # Allow masterpid context managers to run in this case, since we're
     # explicitly designed for this cleanup.
-    cros_build_lib.MasterPidContextManager.ALTERNATE_MASTER_PID = os.getpid()
+    cros_build_lib.PrimaryPidContextManager.ALTERNATE_PRIMARY_PID = os.getpid()
 
     raise RuntimeError('Parent exited uncleanly; forcing cleanup code to run.')
 
diff --git a/lib/commandline.py b/lib/commandline.py
index efed24c..ec73259 100644
--- a/lib/commandline.py
+++ b/lib/commandline.py
@@ -992,7 +992,7 @@
   Args:
     find_target_func: a function, which, when given the absolute
       pathway the script was invoked via (for example,
-      /home/ferringb/cros/trunk/chromite/bin/cros_sdk; note that any
+      /home/ferringb/chromiumos/chromite/bin/cros_sdk; note that any
       trailing .py from the path name will be removed),
       will return the main function to invoke (that functor will take
       a single arg- a list of arguments, and shall return either None
diff --git a/lib/completers/build_target_completers.py b/lib/completers/build_target_completers.py
new file mode 100644
index 0000000..8cf6a7e
--- /dev/null
+++ b/lib/completers/build_target_completers.py
@@ -0,0 +1,35 @@
+# Copyright 2021 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Completer functions to use with --b, --board, --build-target."""
+
+import os
+import re
+from pathlib import Path
+from typing import Iterator, List
+
+from chromite.lib import constants
+from chromite.lib import path_util
+from chromite.lib import portage_util
+
+
+def build_target(prefix, action, parser, parsed_args) -> List[str]:  # pylint: disable=unused-argument
+  """List all possible build targets."""
+  RE_NAME = re.compile(r'^overlay-(.*?)(-private)?$')
+  overlay_paths = portage_util.FindOverlays(constants.BOTH_OVERLAYS)
+  overlays = [os.path.basename(x) for x in overlay_paths]
+  build_targets = set()
+  for overlay in overlays:
+    m = RE_NAME.match(overlay)
+    if m and not m.group(1).startswith('variant-') and m.group(1).startswith(
+        prefix):
+      build_targets.add(m.group(1))
+  return sorted(build_targets)
+
+
+def built_build_target(prefix, action, parser, parsed_args) -> Iterator[str]:  # pylint: disable=unused-argument
+  """List build targets with a sysroot."""
+  p = f'{prefix}*/etc/portage'
+  yield from (x.parent.parent.name for x in Path(
+      path_util.FromChrootPath(path_util.FromChrootPath('/build'))).glob(p))
diff --git a/lib/completers/build_target_completers_unittest.py b/lib/completers/build_target_completers_unittest.py
new file mode 100644
index 0000000..273965c
--- /dev/null
+++ b/lib/completers/build_target_completers_unittest.py
@@ -0,0 +1,54 @@
+# Copyright 2021 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Tests for build_target_completers."""
+
+from pathlib import Path
+
+from chromite.lib import constants
+from chromite.lib import path_util
+from chromite.lib import portage_util
+from chromite.lib.completers import build_target_completers
+
+
+def test_build_target(monkeypatch):
+  """Test that expected build targets are returned from overlays."""
+
+  def mock_find_overlays(overlay_type, *_args, **_kwargs):
+    assert overlay_type == constants.BOTH_OVERLAYS
+    return [
+        '/overlays/overlay-overlay1',
+        '/overlays/overlay-overlay2',
+        '/overlays/overlay-variant-overlay3',
+        '/overlays/overlay-overlay2-private',
+        '/overlays/overlay-test'
+        '/overlays/project-testproject',
+    ]
+
+  monkeypatch.setattr(portage_util, 'FindOverlays', mock_find_overlays)
+  expected_build_targets = ['overlay1', 'overlay2']
+
+  build_targets = build_target_completers.build_target('overlay', None, None,
+                                                       None)
+
+  assert build_targets == expected_build_targets
+
+
+def test_built_build_target(monkeypatch, tmp_path):
+  """Test that only built build targets are returned."""
+
+  def mock_path(path, *_args, **_kwargs):
+    assert path == Path(path_util.FromChrootPath('/build'))
+    return [
+        Path(tmp_path) / 'sysroot1' / 'etc' / 'portage',
+        Path(tmp_path) / 'sysroot2' / 'etc' / 'portage',
+    ]
+
+  monkeypatch.setattr(Path, 'glob', mock_path)
+  expected_built_build_targets = ['sysroot1', 'sysroot2']
+
+  built_build_targets = list(
+      build_target_completers.built_build_target('', None, None, None))
+
+  assert built_build_targets == expected_built_build_targets
diff --git a/lib/completers/package_completers.py b/lib/completers/package_completers.py
new file mode 100644
index 0000000..f8d8db7
--- /dev/null
+++ b/lib/completers/package_completers.py
@@ -0,0 +1,51 @@
+# Copyright 2021 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Completer functions to use with -p, --packages."""
+
+import argparse
+from pathlib import Path
+from typing import Iterator, List
+
+from chromite.lib import build_target_lib
+from chromite.lib import portage_util
+from chromite.lib import sysroot_lib
+
+
+def package(prefix, action, parser, parsed_args) -> List[str]:  # pylint: disable=unused-argument
+  """List all packages with the package version."""
+  packages = (
+      portage_util.SplitEbuildPath(x) for x in _get_ebuilds(parsed_args))
+  return [f'{cat}/{pv}' for (cat, _, pv) in packages]
+
+
+def package_atom(prefix, action, parser, parsed_args) -> List[str]:  # pylint: disable=unused-argument
+  """List all packages without the package version."""
+  return [portage_util.EbuildToCP(x) for x in _get_ebuilds(parsed_args)]
+
+
+def _get_sysroot(parsed_args: argparse.Namespace) -> sysroot_lib.Sysroot:
+  """Get the sysroot using the parsed arguments.
+
+  Check to see if the parsed arguments contain arguments that can be used to
+  determine the sysroot path. The sysroot can be specified when there's also
+  a build target argument and should take precedence. --board/--build_target
+  are the old/new names for the same thing so should never both be defined.
+  """
+  sysroot_path = build_target_lib.get_sdk_sysroot_path()
+  if hasattr(parsed_args, 'sysroot') and parsed_args.sysroot:
+    sysroot_path = parsed_args.sysroot
+  elif hasattr(parsed_args, 'board') and parsed_args.board:
+    sysroot_path = build_target_lib.get_default_sysroot_path(parsed_args.board)
+  elif hasattr(parsed_args, 'build_target') and parsed_args.build_target:
+    sysroot_path = build_target_lib.get_default_sysroot_path(
+        parsed_args.build_target)
+  return sysroot_lib.Sysroot(sysroot_path)
+
+
+def _get_ebuilds(parsed_args: argparse.Namespace) -> Iterator[Path]:
+  """Get ebuild files using the parsed arguments."""
+  sysroot = _get_sysroot(parsed_args)
+  overlay_paths = sysroot.get_overlays()
+  yield from portage_util.FindEbuildsForOverlays(overlay_paths)
diff --git a/lib/completers/package_completers_unittest.py b/lib/completers/package_completers_unittest.py
new file mode 100644
index 0000000..249b237
--- /dev/null
+++ b/lib/completers/package_completers_unittest.py
@@ -0,0 +1,87 @@
+# Copyright 2021 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Tests for package_completers."""
+
+import argparse
+from pathlib import Path
+from typing import Callable, List
+
+import pytest
+
+from chromite.lib import portage_util
+from chromite.lib import sysroot_lib
+from chromite.lib.completers import package_completers
+
+# Pytest's method of declaring fixtures causes Pylint to complain about
+# redefined outer names.
+# pylint: disable=redefined-outer-name
+
+
+class MockSysroot:
+  """Class to mock a Sysroot object for testing."""
+
+  def get_overlays(self):
+    return [
+        '/test/path/overlay1',
+        '/test/path/overlay2',
+    ]
+
+
+@pytest.fixture
+def simple_parser() -> argparse.ArgumentParser:
+  """Create a simple parser with arguments needed for testing."""
+  parser = argparse.ArgumentParser()
+  parser.add_argument('--sysroot')
+  parser.add_argument('--board')
+  parser.add_argument('--build-target')
+  parser.add_argument('--foo')
+  return parser
+
+
+@pytest.fixture
+def get_ebuilds() -> Callable:
+  """Returns ebuild files for testing."""
+
+  def mock_return(*_args, **_kwargs) -> List[Path]:
+    return [
+        Path('/package1/bar1/bar1-1.0.ebuild'),
+        Path('/package2/bar2/bar2-2.0.ebuild'),
+    ]
+
+  return mock_return
+
+
+def test_package(monkeypatch, get_ebuilds, simple_parser):
+  """Test that the package completer returns packages with versions."""
+
+  def mock_sysroot(sysroot_path, *_args, **_kwargs):
+    assert sysroot_path == '/build/grunt'
+    return MockSysroot()
+
+  monkeypatch.setattr(sysroot_lib, 'Sysroot', mock_sysroot)
+  monkeypatch.setattr(portage_util, 'FindEbuildsForOverlays', get_ebuilds)
+  expected_packages = ['package1/bar1-1.0', 'package2/bar2-2.0']
+
+  packages = package_completers.package(
+      None, None, None, simple_parser.parse_args(['--board', 'grunt']))
+
+  assert packages == expected_packages
+
+
+def test_package_atom(monkeypatch, get_ebuilds, simple_parser):
+  """Test that the package atom completer returns packages without versions."""
+
+  def mock_sysroot(sysroot_path, *_args, **_kwargs):
+    assert sysroot_path == '/'
+    return MockSysroot()
+
+  monkeypatch.setattr(sysroot_lib, 'Sysroot', mock_sysroot)
+  monkeypatch.setattr(portage_util, 'FindEbuildsForOverlays', get_ebuilds)
+  expected_packages = ['package1/bar1', 'package2/bar2']
+
+  packages = package_completers.package_atom(
+      None, None, None, simple_parser.parse_args(['--foo', 'bar']))
+
+  assert packages == expected_packages
diff --git a/lib/config_lib.py b/lib/config_lib.py
index 75f7ebb..5d0fea1 100644
--- a/lib/config_lib.py
+++ b/lib/config_lib.py
@@ -801,6 +801,10 @@
       # Android package name.
       android_package=None,
 
+      # Update Android LKGB instead of uprevving the Android package. See
+      # Phase 2 migration of go/android-uprev-recipes.
+      android_update_lkgb=False,
+
       # Uprev Chrome, values of 'tot', 'stable_release', or None.
       chrome_rev=None,
 
diff --git a/lib/constants.py b/lib/constants.py
index 4f3a8b0..0d75aed 100644
--- a/lib/constants.py
+++ b/lib/constants.py
@@ -390,12 +390,8 @@
     TARGET_OS_FACTORY_SHIM_PKG,
 )
 
-# Constants for uprevving Chrome
-
-CHROMEOS_BASE = 'chromeos-base'
-
 # Portage category and package name for Chrome.
-CHROME_CN = CHROMEOS_BASE
+CHROME_CN = 'chromeos-base'
 CHROME_PN = 'chromeos-chrome'
 CHROME_CP = '%s/%s' % (CHROME_CN, CHROME_PN)
 
@@ -689,7 +685,7 @@
 # have sudo export if existent. Anytime this list is modified, a new
 # chroot_version_hooks.d upgrade script that symlinks to 153_rewrite_sudoers.d
 # should be created.
-CHROOT_ENVIRONMENT_WHITELIST = (
+CHROOT_ENVIRONMENT_ALLOWLIST = (
     'CHROMEOS_OFFICIAL',
     'CHROMEOS_VERSION_AUSERVER',
     'CHROMEOS_VERSION_DEVSERVER',
@@ -799,6 +795,8 @@
 # This is the image type mapping to the factory image type in build_image.
 IMAGE_TYPE_FACTORY_SHIM = 'factory_install'
 IMAGE_TYPE_FIRMWARE = 'firmware'
+# Firmware for cros hps device src/platform/hps-firmware2.
+IMAGE_TYPE_HPS_FIRMWARE = 'hps_firmware'
 # USB PD accessory microcontroller firmware (e.g. power brick, display dongle).
 IMAGE_TYPE_ACCESSORY_USBPD = 'accessory_usbpd'
 # Standalone accessory microcontroller firmware (e.g. wireless keyboard).
@@ -943,6 +941,15 @@
 QUICK_PROVISION_PAYLOAD_ROOTFS = 'full_dev_part_ROOT.bin.gz'
 QUICK_PROVISION_PAYLOAD_MINIOS = 'full_dev_part_MINIOS.bin.gz'
 
+# Provenance bundle name. This file name should never be changed, since the
+# signer needs to know where to look for provenance.
+# This is generated via the generate_attestations function in build_menu.
+# This archive contains one JSON file per artifact of interest: image,
+# update payload, etc. It ends up in the expected location because
+# the provenance generation function parses the build_api response to ensure
+# that if they exist, the manifests will be uploaded to GCS.
+ARTIFACT_PROVENANCE_MANIFESTS = 'artifact_provenance_manifests.tar'
+
 # Mock build and stage IDs.
 MOCK_STAGE_ID = 313377
 MOCK_BUILD_ID = 31337
@@ -964,7 +971,7 @@
 }
 
 # Percentage of child builders that need to complete to update LKGM
-LKGM_THRESHOLD = 80
+LKGM_THRESHOLD = 50
 
 # Dev key related names.
 VBOOT_DEVKEYS_DIR = os.path.join('/usr/share/vboot/devkeys')
diff --git a/lib/cros_build_lib.py b/lib/cros_build_lib.py
index 9c337e1..4ed9d80 100644
--- a/lib/cros_build_lib.py
+++ b/lib/cros_build_lib.py
@@ -404,7 +404,7 @@
   """
 
 
-def sudo_run(cmd, user='root', preserve_env=False, **kwargs):
+def sudo_run(cmd, user='root', preserve_env=False, **kwargs) -> CommandResult:
   """Run a command via sudo.
 
   Client code must use this rather than coming up with their own run
@@ -608,7 +608,7 @@
         check=True, int_timeout=1, kill_timeout=1,
         log_output=False, capture_output=False,
         quiet=False, encoding=None, errors=None, dryrun=False,
-        **kwargs):
+        **kwargs) -> CommandResult:
   """Runs a command.
 
   Args:
@@ -873,25 +873,33 @@
                                       kill_timeout, cmd, old_sigterm))
 
     try:
-      (cmd_result.stdout, cmd_result.stderr) = proc.communicate(input)
-    finally:
-      if use_signals:
-        signal.signal(signal.SIGINT, old_sigint)
-        signal.signal(signal.SIGTERM, old_sigterm)
+      try:
+        (cmd_result.stdout, cmd_result.stderr) = proc.communicate(input)
+      finally:
+        if use_signals:
+          signal.signal(signal.SIGINT, old_sigint)
+          signal.signal(signal.SIGTERM, old_sigterm)
 
-      if (popen_stdout and not isinstance(popen_stdout, int) and
-          not log_stdout_to_file):
-        popen_stdout.seek(0)
-        cmd_result.stdout = popen_stdout.read()
-        popen_stdout.close()
-      elif log_stdout_to_file:
-        popen_stdout.close()
+        if (popen_stdout and not isinstance(popen_stdout, int) and
+            not log_stdout_to_file):
+          popen_stdout.seek(0)
+          cmd_result.stdout = popen_stdout.read()
+          popen_stdout.close()
+        elif log_stdout_to_file:
+          popen_stdout.close()
 
-      if (popen_stderr and not isinstance(popen_stderr, int) and
-          not log_stderr_to_file):
-        popen_stderr.seek(0)
-        cmd_result.stderr = popen_stderr.read()
-        popen_stderr.close()
+        if (popen_stderr and not isinstance(popen_stderr, int) and
+            not log_stderr_to_file):
+          popen_stderr.seek(0)
+          cmd_result.stderr = popen_stderr.read()
+          popen_stderr.close()
+    except TerminateRunCommandError as e:
+      # If we were killed by a signal (like SIGTERM in case of a timeout), don't
+      # swallow the output completely as it can be a huge help for figuring out
+      # why the command failed.
+      e.stdout = e.result.stdout = cmd_result.stdout
+      e.stderr = e.result.stderr = cmd_result.stderr
+      raise
 
     cmd_result.returncode = proc.returncode
 
@@ -1503,13 +1511,13 @@
 
 
 # Suppress whacked complaints about abstract class being unused.
-class MasterPidContextManager(object):
+class PrimaryPidContextManager(object):
   """Allow context managers to restrict their exit to within the same PID."""
 
   # In certain cases we actually want this ran outside
   # of the main pid- specifically in backup processes
   # doing cleanup.
-  ALTERNATE_MASTER_PID = None
+  ALTERNATE_PRIMARY_PID = None
 
   def __init__(self):
     self._invoking_pid = None
@@ -1520,7 +1528,7 @@
 
   def __exit__(self, exc_type, exc, exc_tb):
     curpid = os.getpid()
-    if curpid == self.ALTERNATE_MASTER_PID:
+    if curpid == self.ALTERNATE_PRIMARY_PID:
       self._invoking_pid = curpid
     if curpid == self._invoking_pid:
       return self._exit(exc_type, exc, exc_tb)
diff --git a/lib/cros_collections_unittest.py b/lib/cros_collections_unittest.py
index a024bcf..dfd112d 100644
--- a/lib/cros_collections_unittest.py
+++ b/lib/cros_collections_unittest.py
@@ -135,20 +135,20 @@
   def testInvertDictionary(self):
     """Test InvertDictionary."""
     changes = ['change_1', 'change_2', 'change_3', 'change_4']
-    slaves = ['slave_1', 'slave_2', 'slave_3', 'slave_4']
-    slave_changes_dict = {
-        slaves[0]: set(changes[0:1]),
-        slaves[1]: set(changes[0:2]),
-        slaves[2]: set(changes[2:4]),
-        slaves[3]: set()
+    children = ['child_1', 'child_2', 'child_3', 'child_4']
+    child_changes_dict = {
+        children[0]: set(changes[0:1]),
+        children[1]: set(changes[0:2]),
+        children[2]: set(changes[2:4]),
+        children[3]: set()
     }
-    change_slaves_dict = cros_collections.InvertDictionary(
-        slave_changes_dict)
+    change_children_dict = cros_collections.InvertDictionary(
+        child_changes_dict)
 
     expected_dict = {
-        changes[0]: set(slaves[0:2]),
-        changes[1]: set([slaves[1]]),
-        changes[2]: set([slaves[2]]),
-        changes[3]: set([slaves[2]])
+        changes[0]: set(children[0:2]),
+        changes[1]: set([children[1]]),
+        changes[2]: set([children[2]]),
+        changes[3]: set([children[2]])
     }
-    self.assertDictEqual(change_slaves_dict, expected_dict)
+    self.assertDictEqual(change_children_dict, expected_dict)
diff --git a/lib/cros_event.py b/lib/cros_event.py
index 63e6d42..25c0cb4 100644
--- a/lib/cros_event.py
+++ b/lib/cros_event.py
@@ -10,6 +10,8 @@
 import json
 import multiprocessing
 
+from chromite.lib import parallel
+
 
 # Static Keys and Strings
 EVENT_ID = 'id'
@@ -29,10 +31,7 @@
 # Helper functions
 def EventIdGenerator():
   """Returns multiprocess safe iterator that  generates locally unique id"""
-  # NOTE: that is might be as issue if chromite libraries are imported.
-  #       Update to chromite.lib.parallel.Manager().Value('i') if this
-  #       becomes an issue
-  eid = multiprocessing.Value('i', 1)
+  eid = parallel.WrapMultiprocessing(multiprocessing.Value, 'i', 1)
 
   while True:
     with eid.get_lock():
diff --git a/lib/cros_sdk_lib.py b/lib/cros_sdk_lib.py
index 1434460..60244f3 100644
--- a/lib/cros_sdk_lib.py
+++ b/lib/cros_sdk_lib.py
@@ -41,6 +41,10 @@
 _MAX_LVM_RETRIES = 3
 
 
+# Bash completion directory.
+_BASH_COMPLETION_DIR = (
+    f'{constants.CHROOT_SOURCE_ROOT}/chromite/sdk/etc/bash_completion.d')
+
 class Error(Exception):
   """Base cros sdk error class."""
 
@@ -203,8 +207,14 @@
   osutils.Mount('sysfs', path / 'sys', 'sysfs', defflags)
 
   if 'binfmt_misc' in KNOWN_FILESYSTEMS:
-    osutils.Mount('binfmt_misc', path / 'proc/sys/fs/binfmt_misc',
-                  'binfmt_misc', defflags)
+    try:
+      osutils.Mount('binfmt_misc', path / 'proc/sys/fs/binfmt_misc',
+                    'binfmt_misc', defflags)
+    except PermissionError:
+      # We're in an environment where we can't mount binfmt_misc (e.g. a
+      # container), so ignore it for now.  We need it for unittests via qemu,
+      # but nothing else currently.
+      pass
 
   if 'configfs' in KNOWN_FILESYSTEMS:
     osutils.Mount('configfs', path / 'sys/kernel/config', 'configfs', defflags)
@@ -565,7 +575,7 @@
 
   # If we didn't find a mounted VG before but we did find a loopback device,
   # re-check for a VG attached to the loopback.
-  if not vg_name:
+  if not vg_name and chroot_dev:
     vg_name = FindVolumeGroupForDevice(chroot, chroot_dev)
     if vg_name:
       cmd = ['vgs', vg_name]
@@ -690,6 +700,8 @@
       except ValueError:
         raise InvalidChrootVersionError(
             'Invalid chroot version in %s: %s' % (self._version_file, version))
+      else:
+        logging.debug('Found chroot version %s', self._version)
 
     return self._version
 
@@ -954,29 +966,17 @@
     (home / 'chromiumos').symlink_to(constants.CHROOT_SOURCE_ROOT)
     (home / 'depot_tools').symlink_to('/mnt/host/depot_tools')
 
-    # Automatically change to scripts directory.
     bash_profile = home / '.bash_profile'
     osutils.Touch(bash_profile)
     data = bash_profile.read_text().rstrip()
     if data:
       data += '\n\n'
+    # Automatically change to scripts directory.
     data += (
-        'cd "${CHROOT_CWD:-${HOME}/chromiumos/src/scripts}"\n'
+        'cd "${CHROOT_CWD:-${HOME}/chromiumos/src/scripts}"\n\n'
     )
     bash_profile.write_text(data)
 
-    # Enable bash completion.
-    bashrc = home / '.bashrc'
-    osutils.Touch(bashrc)
-    data = bashrc.read_text().rstrip()
-    if data:
-      data += '\n\n'
-    data += (
-        '# Set up bash autocompletion.\n'
-        '. ~/chromiumos/src/scripts/bash_completion\n'
-    )
-    bashrc.write_text(data)
-
     osutils.Chown(home, user=uid, group=gid, recursive=True)
 
   def init_filesystem_basic(self):
@@ -1027,6 +1027,11 @@
         f'{constants.CHROOT_SOURCE_ROOT}/chromite/sdk/etc/profile.d/'
         '50-chromiumos-niceties.sh')
 
+    # Enable bash completion.
+    bash_completion_d = etc_dir / 'bash_completion.d'
+    bash_completion_d.mkdir(mode=0o755, parents=True, exist_ok=True)
+    (bash_completion_d / 'cros').symlink_to(f'{_BASH_COMPLETION_DIR}/cros')
+
     # Select a small set of locales for the user if they haven't done so
     # already.  This makes glibc upgrades cheap by only generating a small
     # set of locales.  The ones listed here are basically for the buildbots
diff --git a/lib/cros_sdk_lib_unittest.py b/lib/cros_sdk_lib_unittest.py
index eb3e596..9b01831 100644
--- a/lib/cros_sdk_lib_unittest.py
+++ b/lib/cros_sdk_lib_unittest.py
@@ -646,7 +646,7 @@
           self.chroot_path, None, proc_mounts=proc_mounts)
 
     m.assert_called_with(self.chroot_path)
-    m2.assert_called_with(self.chroot_path, None)
+    m2.assert_not_called()
 
   def testNothingCleanupWithDelete(self):
     m = self.PatchObject(osutils, 'UmountTree')
@@ -668,7 +668,7 @@
           self.chroot_path, None, delete=True, proc_mounts=proc_mounts)
 
     m.assert_called_with(self.chroot_path)
-    m2.assert_called_with(self.chroot_path, None)
+    m2.assert_not_called()
     m3.assert_called_with(self.chroot_img)
     m4.assert_called_with(self.chroot_path, ignore_missing=True, sudo=True)
 
@@ -862,6 +862,8 @@
     self.assertExists(etc / 'mtab')
     self.assertIn(f'PORTAGE_USERNAME="{TEST_USER}"',
                   (etc / 'env.d' / '99chromiumos').read_text())
+    self.assertEqual('/mnt/host/source/chromite/sdk/etc/bash_completion.d/cros',
+                     os.readlink(etc / 'bash_completion.d' / 'cros'))
     self.assertIn('en_US.UTF-8 UTF-8', (etc / 'locale.gen').read_text())
 
   def testExistingCompatGroup(self):
diff --git a/lib/cros_test.py b/lib/cros_test.py
index ddc95fd..667d36a 100644
--- a/lib/cros_test.py
+++ b/lib/cros_test.py
@@ -8,6 +8,7 @@
 import logging
 import os
 
+from chromite.cbuildbot import commands
 from chromite.cli.cros import cros_chrome_sdk
 from chromite.lib import chrome_util
 from chromite.lib import constants
@@ -54,6 +55,9 @@
     self.tast_vars = opts.tast_vars
     self.tast_total_shards = opts.tast_total_shards
     self.tast_shard_index = opts.tast_shard_index
+    self.tast_extra_use_flags = []
+    if opts.tast_extra_use_flags:
+      self.tast_extra_use_flags = opts.tast_extra_use_flags.split(',')
     self.results_dir = opts.results_dir
     self.test_that_args = opts.test_that_args
     self.test_timeout = opts.test_timeout
@@ -350,12 +354,15 @@
 
     if self._device.log_level == 'debug':
       cmd += ['-verbose']
-    cmd += ['run', '-build=false', '-waituntilready',
-      # Skip tests depending on private runtime variables.
-      # 'gs://chromeos-prebuilt/board/amd64-host/.../chromeos-base/tast-vars*'
-      # doesn't contain runtime variable files in the tast-tests-private
-      # repository.
-      r'-maybemissingvars=.+\..+',
+    cmd += [
+        'run',
+        '-build=false',
+        '-waituntilready',
+        # Skip tests depending on private runtime variables.
+        # 'gs://chromeos-prebuilt/board/amd64-host/.../chromeos-base/tast-vars*'
+        # doesn't contain runtime variable files in the tast-tests-private
+        # repository.
+        r'-maybemissingvars=.+\..+',
     ]
     # If the tests are not informational, then fail on test failure.
     # TODO(dhanyaganesh@): Make this less hack-y crbug.com/1034403.
@@ -388,17 +395,27 @@
       # gsutil onto path during the test.
       gsutil_dir = constants.CHROMITE_SCRIPTS_DIR
       extra_env = {'PATH': os.environ.get('PATH', '') + ':' + gsutil_dir}
+
+      tast_vars_dir = cros_chrome_sdk.SDKFetcher.GetCachePath(
+          commands.AUTOTEST_SERVER_PACKAGE, self.cache_dir, self._device.board)
+      tast_vars_dir = os.path.join(tast_vars_dir, 'tast', 'vars', 'private')
+      if os.path.exists(tast_vars_dir):
+        cmd += ['-defaultvarsdir=%s' % tast_vars_dir]
     else:
       extra_env = None
 
     if self.test_timeout > 0:
       cmd += ['-timeout=%d' % self.test_timeout]
-    # This flag is needed when running Tast tests on VMs. Note that this check
-    # is only true if we're handling VM start-up/tear-down ourselves for the
-    # duration of the test. If the caller has already launched a VM themselves
-    # and has pointed the '--device' arg at it, this check will be false.
-    if self._device.should_start_vm:
-      cmd += ['-extrauseflags=tast_vm']
+    if (self._device.should_start_vm and
+        'tast_vm' not in self.tast_extra_use_flags):
+      # The 'tast_vm' flag is needed when running Tast tests on VMs. Note that
+      # this check is only true if we're handling VM start-up/tear-down
+      # ourselves for the duration of the test. If the caller has already
+      # launched a VM themselves and has pointed the '--device' arg at it, this
+      # check will be false.
+      self.tast_extra_use_flags.append('tast_vm')
+    if self.tast_extra_use_flags:
+      cmd += ['-extrauseflags=%s' % ','.join(self.tast_extra_use_flags)]
     if self.results_dir:
       results_dir = self.results_dir
       if need_chroot:
@@ -600,6 +617,9 @@
                       help='Shard index to use when running Tast tests.')
   parser.add_argument('--tast-total-shards', type=int, default=0,
                       help='Total number of shards when running Tast tests.')
+  parser.add_argument('--tast-extra-use-flags',
+                      help='Comma-separated list of extra USE flags to pass to '
+                      'Tast when running tests.')
   parser.add_argument('--chrome-test', action='store_true', default=False,
                       help='Run chrome test on device. The first arg in the '
                       'remote command should be the test binary name, such as '
diff --git a/lib/cros_test_unittest.py b/lib/cros_test_unittest.py
index e579b89..6e2e3f0 100644
--- a/lib/cros_test_unittest.py
+++ b/lib/cros_test_unittest.py
@@ -9,6 +9,7 @@
 
 import pytest  # pylint: disable=import-error
 
+from chromite.cbuildbot import commands
 from chromite.lib import constants
 from chromite.lib import cros_test
 from chromite.lib import cros_test_lib
@@ -433,10 +434,12 @@
     self._tester.results_dir = '/tmp/results'
     self._tester.tast_total_shards = 2
     self._tester.tast_shard_index = 1
+    self._tester.tast_extra_use_flags = ['some_flag1', 'some_flag2']
     self._tester.Run()
     check_inside_chroot_mock.assert_called()
     self.assertCommandContains(['tast', '-verbose', 'run', '-build=false',
                                 '-waituntilready', '-timeout=100',
+                                '-extrauseflags=some_flag1,some_flag2',
                                 '-resultsdir', '/tmp/results', '-totalshards=2',
                                 '-shardindex=1', '100.90.29.199',
                                 'ui.ChromeLogin'])
@@ -445,11 +448,15 @@
     """Verify running tast tests from the SimpleChrome SDK."""
     self._tester.tast = ['ui.ChromeLogin']
     self._tester._device.private_key = '/tmp/.ssh/testing_rsa'
-    tast_cache_dir = cros_test_lib.FakeSDKCache(
-        self._tester.cache_dir).CreateCacheReference(
-            self._tester._device.board, 'chromeos-base')
+    fake_cache = cros_test_lib.FakeSDKCache(self._tester.cache_dir)
+    tast_cache_dir = fake_cache.CreateCacheReference(
+        self._tester._device.board, 'chromeos-base')
     tast_bin_dir = os.path.join(tast_cache_dir, 'tast-cmd/usr/bin')
     osutils.SafeMakedirs(tast_bin_dir)
+    tast_vars_dir = fake_cache.CreateCacheReference(
+        self._tester._device.board, commands.AUTOTEST_SERVER_PACKAGE)
+    tast_vars_dir = os.path.join(tast_vars_dir, 'tast', 'vars', 'private')
+    osutils.SafeMakedirs(tast_vars_dir)
     self._tester.Run()
     self.assertCommandContains([
         os.path.join(tast_bin_dir,
@@ -461,6 +468,7 @@
         '-remotedatadir=%s' % os.path.join(
             tast_cache_dir, 'tast-remote-tests-cros/usr', 'share/tast/data'),
         '-ephemeraldevserver=true', '-keyfile', '/tmp/.ssh/testing_rsa',
+        '-defaultvarsdir=%s' % tast_vars_dir,
         '-extrauseflags=tast_vm', 'localhost:9222', 'ui.ChromeLogin'
     ])
 
diff --git a/lib/dependency_lib.py b/lib/dependency_lib.py
index 4d848c5..c2d301a 100644
--- a/lib/dependency_lib.py
+++ b/lib/dependency_lib.py
@@ -150,7 +150,7 @@
 
   Returns:
     Map from each package to the source path (relative to the repo checkout
-      root, i.e: ~/trunk/ in your cros_sdk) it depends on.
+      root, i.e: ~/chromiumos/ in your cros_sdk) it depends on.
     For each source path which is a directory, the string is ended with a
       trailing '/'.
   """
diff --git a/lib/depgraph.py b/lib/depgraph.py
index 41c2f1e..f3d7353 100644
--- a/lib/depgraph.py
+++ b/lib/depgraph.py
@@ -10,7 +10,7 @@
 import os
 import sys
 import time
-from typing import List, Optional, Union
+from typing import Collection, List, Optional, TYPE_CHECKING, Union
 
 # These aren't available outside the SDK.
 # pylint: disable=import-error
@@ -34,6 +34,12 @@
 from chromite.lib.parser import package_info
 
 
+if TYPE_CHECKING:
+  from chromite.lib import sysroot_lib
+
+PackageCollection = Union[Collection[str], Collection[package_info.PackageInfo]]
+
+
 class DepGraphGenerator(object):
   """Grab dependency information about packages from portage.
 
@@ -120,7 +126,7 @@
         emerge_args.append(arg)
 
     # These packages take a really long time to build, so, for expediency, we
-    # are blacklisting them from automatic rebuilds because one of their
+    # are denylisting them from automatic rebuilds because one of their
     # dependencies needs to be recompiled.
     for pkg in ('chromeos-base/chromeos-chrome',):
       emerge_args.append('--rebuild-exclude=%s' % pkg)
@@ -863,8 +869,7 @@
                                         ('deps', 'bdeps', 'packages'))
 
 
-def _get_emerge_args(sysroot_path: str,
-                     packages: Union[List[str], List[package_info.PackageInfo]],
+def _get_emerge_args(sysroot_path: str, packages: PackageCollection,
                      include_bdeps: bool) -> List[str]:
   """Get the default emerge arguments for building a depgraph."""
   # Pretend: Don't actually install anything.
@@ -914,8 +919,7 @@
 
 
 def _get_raw_sdk_depgraph(
-    packages: Optional[Union[List[str], List[package_info.PackageInfo]]] = None
-) -> DepgraphResult:
+    packages: Optional[PackageCollection] = None) -> DepgraphResult:
   """Get the depgraph for the SDK itself.
 
   The SDK deps will contain the packages installed to a fresh SDK.
@@ -935,8 +939,7 @@
 def _get_raw_sysroot_depgraph(
     sysroot: Optional['sysroot_lib.Sysroot'] = None,
     build_target: Optional['build_target_lib.BuildTarget'] = None,
-    packages: Optional[Union[List[str], List[package_info.PackageInfo]]] = None
-) -> DepgraphResult:
+    packages: Optional[PackageCollection] = None) -> DepgraphResult:
   """Get the sysroot depgraph for a build target.
 
   The sysroot deps are the packages installed to a sysroot -- effectively
@@ -959,8 +962,7 @@
 def _get_raw_build_target_depgraph(
     sysroot: Optional['sysroot_lib.Sysroot'] = None,
     build_target: Optional['build_target_lib.BuildTarget'] = None,
-    packages: Optional[Union[List[str], List[package_info.PackageInfo]]] = None
-) -> DepgraphResult:
+    packages: Optional[PackageCollection] = None) -> DepgraphResult:
   """Get the full depgraph for a build target - its sysroot and bdepends.
 
   The build target deps contains the [r]depends packages installed
@@ -981,21 +983,19 @@
 
 
 def get_sdk_dependency_graph(
-    pkgs: Optional[Union[List[str], List[package_info.PackageInfo]]] = None,
-    with_src_paths: bool = False
-) -> dependency_graph.DependencyGraph:
+    pkgs: Optional[PackageCollection] = None,
+    with_src_paths: bool = False) -> dependency_graph.DependencyGraph:
   """Get the DependencyGraph for the SDK itself."""
   result = _get_raw_sdk_depgraph(packages=pkgs)
-  return _create_graph_from_deps(
-      result.deps, build_target_lib.get_sdk_sysroot_path(),
-      result.packages, with_src_paths)
+  return _create_graph_from_deps(result.deps,
+                                 build_target_lib.get_sdk_sysroot_path(),
+                                 result.packages, with_src_paths)
 
 
 def get_sysroot_dependency_graph(
     sysroot: Union[str, 'sysroot_lib.Sysroot'],
-    packages: Optional[Union[List[str], List[package_info.PackageInfo]]] = None,
-    with_src_paths: bool = False
-) -> dependency_graph.DependencyGraph:
+    packages: Optional[PackageCollection] = None,
+    with_src_paths: bool = False) -> dependency_graph.DependencyGraph:
   """Get the DependencyGraph for the sysroot only."""
   result = _get_raw_sysroot_depgraph(sysroot, packages=packages)
   return _create_graph_from_deps(result.deps, sysroot, result.packages,
@@ -1004,9 +1004,8 @@
 
 def get_build_target_dependency_graph(
     sysroot: Union[str, 'sysroot_lib.Sysroot'],
-    packages: Optional[Union[List[str], List[package_info.PackageInfo]]] = None,
-    with_src_paths: bool = False
-) -> dependency_graph.DependencyGraph:
+    packages: Optional[PackageCollection] = None,
+    with_src_paths: bool = False) -> dependency_graph.DependencyGraph:
   """Get the DependencyGraph for the sysroot and its bdeps."""
   result = _get_raw_build_target_depgraph(sysroot, packages=packages)
   return _create_graph_from_deps(result.deps, sysroot, result.packages,
@@ -1015,9 +1014,8 @@
 
 def _create_graph_from_deps(
     deps: dict, sysroot: Union[str, 'sysroot_lib.Sysroot'],
-    packages: Union[List[str], List[package_info.PackageInfo]],
-    with_src_paths: bool
-) -> dependency_graph.DependencyGraph:
+    packages: PackageCollection,
+    with_src_paths: bool) -> dependency_graph.DependencyGraph:
   """Create DependencyGraph from the raw DepGraphGenerator deps.
 
   Translate the raw DepGraphGenerator deps into PackageNodes for a
diff --git a/lib/dev_server_wrapper.py b/lib/dev_server_wrapper.py
index 2b5b75a..49191d2 100644
--- a/lib/dev_server_wrapper.py
+++ b/lib/dev_server_wrapper.py
@@ -269,32 +269,9 @@
     Args:
       static_dir: path to the static directory of the devserver instance.
     """
-    cls.WipePayloadCache(static_dir=static_dir)
     logging.info('Clearing cache directory %s', static_dir)
     osutils.RmDir(static_dir, ignore_missing=True, sudo=True)
 
-  @classmethod
-  def WipePayloadCache(cls, devserver_bin='start_devserver', static_dir=None):
-    """Cleans up devserver cache of payloads.
-
-    This isn't necessary for chrome checkouts.
-
-    Args:
-      devserver_bin: path to the devserver binary.
-      static_dir: path to use as the static directory of the devserver instance.
-    """
-    if path_util.DetermineCheckout().type == path_util.CHECKOUT_TYPE_GCLIENT:
-      return
-
-    logging.info('Cleaning up previously generated payloads.')
-    cmd = [devserver_bin, '--clear_cache', '--exit']
-    if static_dir:
-      cmd.append('--static_dir=%s' % path_util.ToChrootPath(static_dir))
-
-    cros_build_lib.sudo_run(
-        cmd, enter_chroot=True, print_cmd=False, stderr=subprocess.STDOUT,
-        stdout=True, cwd=constants.SOURCE_ROOT)
-
   def _ReadPortNumber(self):
     """Read port number from file."""
     if not self.is_alive():
diff --git a/lib/dlc_lib.py b/lib/dlc_lib.py
index 8dd181b..a9830e8 100644
--- a/lib/dlc_lib.py
+++ b/lib/dlc_lib.py
@@ -22,8 +22,11 @@
 
 
 DLC_BUILD_DIR = 'build/rootfs/dlc'
+DLC_FACTORY_INSTALL_DIR = 'unencrypted/dlc-factory-images'
+DLC_GID = 20118
 DLC_IMAGE = 'dlc.img'
 DLC_META_DIR = 'opt/google/dlc'
+DLC_UID = 20118
 DLC_TMP_META_DIR = 'meta'
 EBUILD_PARAMETERS = 'ebuild_parameters.json'
 IMAGELOADER_JSON = 'imageloader.json'
@@ -101,13 +104,15 @@
     used_by: (str) The user of this DLC, e.g. "system" or "user"
     days_to_purge: (int) The number of days to keep a DLC after uninstall and
         before it is purged.
+    reserved: (bool) always reserve space for DLC on disk.
+    critical_update: (bool) DLC always updates with the OS.
     fullnamerev: (str) The full package & version name.
   """
 
   def __init__(self, dlc_id, dlc_package, fs_type, pre_allocated_blocks,
                version, name, description, preload, used_by,
-               mount_file_required, fullnamerev, days_to_purge=0,
-               factory_install=False):
+               mount_file_required, fullnamerev, reserved=False,
+               critical_update=False, days_to_purge=0, factory_install=False):
     """Initializes the object.
 
     When adding a new variable in here, always set a default value. The reason
@@ -128,6 +133,8 @@
     self.mount_file_required = mount_file_required
     self.fullnamerev = fullnamerev
     self.days_to_purge = days_to_purge
+    self.reserved = reserved
+    self.critical_update = critical_update
 
   def StoreDlcParameters(self, install_root_dir, sudo):
     """Store DLC parameters defined in the ebuild.
@@ -382,9 +389,14 @@
     licensing.LoadPackageInfo()
     licensing.ProcessPackageLicenses()
     license_path = os.path.join(dlc_dir, LICENSE)
+    licenses = licensing.GenerateLicenseText()
     # The first (and only) item contains the values for |self.fullnamerev|.
-    _, license_txt = next(iter(licensing.GenerateLicenseText().items()))
-    osutils.WriteFile(license_path, license_txt)
+    if licenses:
+      _, license_txt = next(iter(licenses.items()))
+      osutils.WriteFile(license_path, license_txt)
+    else:
+      logging.info('LICENSE text is empty. Skipping LICENSE file creation.')
+
 
   def CollectExtraResources(self, dlc_dir):
     """Collect the extra resources needed by the DLC module.
@@ -478,6 +490,8 @@
         'used-by': self.ebuild_params.used_by,
         'days-to-purge': self.ebuild_params.days_to_purge,
         'mount-file-required': self.ebuild_params.mount_file_required,
+        'reserved': self.ebuild_params.reserved,
+        'critical-update': self.ebuild_params.critical_update,
     }
 
   def GenerateVerity(self):
@@ -674,8 +688,9 @@
       # Factory install DLCs.
       if (stateful and factory_install and
           IsFactoryInstallAllowed(d_id, dlc_build_dir)):
+        install_stateful_root = os.path.join(stateful, DLC_FACTORY_INSTALL_DIR)
         install_stateful_dir = os.path.join(
-            stateful, 'unencrypted/dlc-factory-images', d_id, d_package)
+            install_stateful_root, d_id, d_package)
         osutils.SafeMakedirs(install_stateful_dir, mode=0o755, sudo=True)
         source_dlc_dir = os.path.join(dlc_build_dir, d_id, d_package)
         for filepath in (os.path.join(source_dlc_dir, fname)
@@ -686,6 +701,13 @@
           cros_build_lib.sudo_run(['cp', filepath, install_stateful_dir],
                                   print_cmd=False, stderr=True)
 
+        # Change the owner + group of factory install directory.
+        # Refer to
+        # http://cs/chromeos_public/src/third_party/eclass-overlay or
+        # DLC/dlcservice related uid + gid.
+        cros_build_lib.sudo_run(['chown', '-R', '%d:%d' % (DLC_UID, DLC_GID),
+                                 install_stateful_root])
+
       # Create metadata directory in rootfs.
       if rootfs:
         meta_rootfs = os.path.join(rootfs, DLC_META_DIR, d_id, d_package)
diff --git a/lib/dlc_lib_unittest.py b/lib/dlc_lib_unittest.py
index 403ecb8..531f61b 100644
--- a/lib/dlc_lib_unittest.py
+++ b/lib/dlc_lib_unittest.py
@@ -74,6 +74,8 @@
         'used_by': dlc_lib.USED_BY_USER,
         'days_to_purge': _DAYS_TO_PURGE,
         'mount_file_required': True,
+        'reserved': False,
+        'critical_update': False,
     }
 
   def testGetParamsPath(self):
@@ -99,6 +101,8 @@
                   used_by=dlc_lib.USED_BY_SYSTEM,
                   days_to_purge=_DAYS_TO_PURGE,
                   mount_file_required=False,
+                  reserved=False,
+                  critical_update=False,
                   fullnamerev=_FULLNAME_REV):
     """Tests EbuildParams JSON values"""
     self.assertDictEqual(ebuild_params,
@@ -114,6 +118,8 @@
                           'used_by': used_by,
                           'days_to_purge': days_to_purge,
                           'mount_file_required': mount_file_required,
+                          'reserved': reserved,
+                          'critical_update': critical_update,
                           'fullnamerev': fullnamerev})
 
   def GenerateParams(self,
@@ -130,6 +136,8 @@
                      used_by=dlc_lib.USED_BY_SYSTEM,
                      days_to_purge=_DAYS_TO_PURGE,
                      mount_file_required=False,
+                     reserved=False,
+                     critical_update=False,
                      fullnamerev=_FULLNAME_REV):
     """Creates and Stores DLC params at install_root_dir"""
     params = dlc_lib.EbuildParams(
@@ -145,6 +153,8 @@
         used_by=used_by,
         days_to_purge=days_to_purge,
         mount_file_required=mount_file_required,
+        reserved=reserved,
+        critical_update=critical_update,
         fullnamerev=fullnamerev)
     return params.StoreDlcParameters(
         install_root_dir=install_root_dir, sudo=False)
@@ -224,6 +234,8 @@
         used_by=dlc_lib.USED_BY_SYSTEM,
         days_to_purge=_DAYS_TO_PURGE,
         mount_file_required=False,
+        reserved=False,
+        critical_update=False,
         fullnamerev=_FULLNAME_REV)
     return dlc_lib.DlcGenerator(
         ebuild_params=params,
@@ -346,6 +358,8 @@
             'factory-install': False,
             'used-by': dlc_lib.USED_BY_SYSTEM,
             'days-to-purge': _DAYS_TO_PURGE,
+            'reserved': False,
+            'critical-update': False,
         })
 
   def testVerifyImageSize(self):
diff --git a/lib/filetype.py b/lib/filetype.py
index 159084e..0ca7a62 100644
--- a/lib/filetype.py
+++ b/lib/filetype.py
@@ -74,7 +74,7 @@
   shared between several calls to that method.
   """
 
-  # Whitelist of mime types and their mapping to file type.
+  # Allowlist of mime types and their mapping to file type.
   MIME_TYPE_MAPPING = {
       'application/x-gzip': 'binary/compressed/gzip',
       'application/x-bzip2': 'binary/compressed/bzip2',
@@ -203,7 +203,7 @@
           first_kib.startswith(b'TZif3' + b'\0' * 15)):
         return 'binary/tzfile'
 
-      # Whitelist some binary mime types.
+      # Allowlist some binary mime types.
       fobj.seek(0)
       # _mime.descriptor() will close the passed file descriptor.
       mime_type = self._mime.descriptor(os.dup(fobj.fileno()))
diff --git a/lib/firmware/README.md b/lib/firmware/README.md
index 243cb50..f6087fb 100644
--- a/lib/firmware/README.md
+++ b/lib/firmware/README.md
@@ -1,96 +1,84 @@
-# AP Firmware sample usage guide:
+# AP Firmware tooling usage guide:
+
+This guide covers how to use `cros ap` tooling.
+If you're interested in changing/fixing config for your board, please refer to
+[ap_firmware_config/README.md](ap_firmware_config/README.md)
 
 ## Building
-To build the AP Firmware for foo:
-  setup_board -b foo # if not set up yet
+To build the AP Firmware for board `foo`:
+```
   cros ap build -b foo
+```
 
-To build the AP Firmware only for foo-variant:
+To build the AP Firmware only for `foo-variant`:
+```
   cros ap build -b foo --fw-name foo-variant
+```
 
 ## Flashing
-Requires servod process to be running if flashing via servo
+Flashing via servo requires servod process to be running.
 
-To flash your zork DUT with an IP of 1.1.1.1 via SSH:
-  cros ap flash -b zork -i /path/to/image.bin -d ssh://1.1.1.1
+To flash a DUT with an IP of 1.1.1.1 via SSH:
+```
+  cros ap flash -b $BOARD -i /path/to/image.bin -d ssh://1.1.1.1
+```
 
-To flash your volteer DUT via SERVO on the default port (9999):
-  cros ap flash -d servo:port -b volteer -i /path/to/image.bin
+To flash a DUT via SERVO on the default port (9999):
+```
+  cros ap flash -d servo:port -b $BOARD -i /path/to/image.bin
+```
 
-To flash your volteer DUT via SERVO on port 1234:
-  cros ap flash -d servo:port:1234 -b volteer -i /path/to/image.bin
+To flash a DUT via SERVO on port 1234:
+```
+  cros ap flash -d servo:port:1234 -b $BOARD -i /path/to/image.bin
+```
 
 To pass additional options to futility or flashrom, provide them after `--`,
 e.g.:
-  cros ap flash -b zork -i /path/to/image.bin -d ssh://1.1.1.1 -- --force
+```
+  cros ap flash -b $BOARD -i /path/to/image.bin -d ssh://1.1.1.1 -- --force
+```
 
 ## Reading
-To read image of device.cros via SSH:
-  cros ap read -b volteer -o /tmp/volteer-image.bin -d ssh://device.cros
+To read firmware image of a DUT with an IP of 1.1.1.1 via SSH:
+```
+  cros ap read -b $BOARD -o /tmp/read-image.bin -d ssh://1.1.1.1
+```
 
 If you don't have ssh access from within the chroot, you may set up ssh tunnel:
-  ssh -L 2222:localhost:22 device.cros
-  cros ap read -b volteer -o /tmp/volteer-image.bin -d ssh://localhost:2222
+```
+  ssh -L 2222:localhost:22 1.1.1.1
+  cros ap read -b $BOARD -o /tmp/read-image.bin -d ssh://localhost:2222
+```
 
 To read image from DUT via SERVO on port 1234:
-  cros ap read -b volteer -o /tmp/volteer-image.bin -d servo:port:1234
+```
+  cros ap read -b $BOARD -o /tmp/read-image.bin -d servo:port:1234
+```
 
 To read a specific region from DUT via SERVO on default port(9999):
-  cros ap read -b volteer -r region -o /tmp/volteer-image.bin -d servo:port
+```
+  cros ap read -b $BOARD -r region -o /tmp/read-image.bin -d servo:port
+```
 
 ## Dumping config
+To dump [AP config](https://source.corp.google.com/chromeos_public/chromite/lib/firmware/ap_firmware_config) of all boards to stdout
+```
+  cros ap dump-config
+```
+
 To dump AP config of all boards into /tmp/cros-read-ap-config.json
+```
   cros ap dump-config -o /tmp/cros-read-ap-config.json
+```
 
 To dump AP config of drallion and dedede boards:
+```
   cros ap dump-config -o /tmp/cros-read-ap-config.json -b "drallion dedede"
+```
 
-## Add support for new board
-Create ${BOARD}.py in chromite/lib/firmware/ap_firmware_config.
-The __template.py file can be copied into place, it contains a skeleton config.
-
- Define the following variables:
-
-    BUILD_WORKON_PACKAGES as a list of all packages that should be cros_workon'd
-      before building.
-
-    BUILD_PACKAGES as a list of all packages that should be emerged during the
-      build process.
-
-  Define the following functions:
-
-    is_fast_required:
-      Only required if it needs to return True for any cases!
-      Returns true if --fast is necessary to flash successfully.
-
-      Args:
-        use_futility (bool): True if futility is to be used, False if
-          flashrom.
-        servo (str): The type name of the servo device being used.
-      Returns:
-        bool: True if fast is necessary, False otherwise.
-
-    get_config:
-      Get specific flash config for this board.
-      Each board needs specific commands including the voltage for Vref, to turn
-      on and turn off the SPI flash. These commands can be found in the care and
-      feeding doc for your board, any command that needs to be run before
-      flashing should be included in dut_control_on and anything run after
-      flashing should be in dut_control_off.
-
-      Args:
-        servo (servo_lib.Servo): The servo connected to the target DUT.
-
-      Returns:
-        servo_lib.FirmwareConfig:
-          dut_control_on: 2d array formatted like [["cmd1", "arg1", "arg2"],
-                                                   ["cmd2", "arg3", "arg4"]]
-                          with commands that need to be ran before flashing,
-                          where cmd1 will be run before cmd2.
-          dut_control_off: 2d array formatted like [["cmd1", "arg1", "arg2"],
-                                                    ["cmd2", "arg3", "arg4"]]
-                          with commands that need to be ran after flashing,
-                          where cmd1 will be run before cmd2.
-          programmer: programmer argument (-p) for flashrom and futility.
-
-See dedede.py for examples of each function/variable.
+## Cleaning
+To unmerge firmware-related packages and clear `/build/$BOARD/firmware` directory:
+```
+cros ap clean -b $BOARD
+```
diff --git a/lib/firmware/ap_firmware.py b/lib/firmware/ap_firmware.py
deleted file mode 100644
index fcd9a7b..0000000
--- a/lib/firmware/ap_firmware.py
+++ /dev/null
@@ -1,391 +0,0 @@
-# Copyright 2020 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""AP firmware utilities."""
-
-import collections
-import importlib
-import logging
-import os
-from typing import Iterable, Optional
-
-from chromite.lib import build_target_lib
-from chromite.lib import cros_build_lib
-from chromite.lib import osutils
-from chromite.lib import portage_util
-from chromite.lib import workon_helper
-from chromite.lib.firmware import flash_ap
-from chromite.service import sysroot
-
-_BUILD_TARGET_CONFIG_MODULE = 'chromite.lib.firmware.ap_firmware_config.%s'
-_CONFIG_BUILD_WORKON_PACKAGES = 'BUILD_WORKON_PACKAGES'
-_CONFIG_BUILD_PACKAGES = 'BUILD_PACKAGES'
-_GENERIC_CONFIG_NAME = 'generic'
-
-# The build configs. The workon and build fields both contain tuples of
-# packages.
-BuildConfig = collections.namedtuple('BuildConfig', ('workon', 'build'))
-
-# The set of commands for a servo deploy.
-ServoDeployCommands = collections.namedtuple('ServoDeployCommands',
-                                             ('dut_on', 'dut_off', 'flash'))
-
-
-class Error(Exception):
-  """Base error class for the module."""
-
-
-class BuildError(Error):
-  """Failure in the build command."""
-
-
-class BuildTargetNotConfiguredError(Error):
-  """Thrown when a config module does not exist for the build target."""
-
-
-class DeployError(Error):
-  """Failure in the deploy command."""
-
-
-class InvalidConfigError(Error):
-  """The config does not contain the required information for the operation."""
-
-
-class CleanError(Error):
-  """Failure in the clean command."""
-
-
-def build(build_target, fw_name=None, dry_run=False):
-  """Build the AP Firmware.
-
-  Args:
-    build_target (BuildTarget): The build target (board) being built.
-    fw_name (str|None): Optionally set the FW_NAME envvar to allow building
-      the firmware for only a specific variant.
-    dry_run (bool): Whether to perform a dry run.
-  """
-  logging.notice('Building AP Firmware.')
-
-  if not os.path.exists(build_target.root):
-    logging.warning('Sysroot for target %s is not available. Attempting '
-                    'to configure sysroot via default setup_board command.',
-                    build_target.name)
-    try:
-      sysroot.SetupBoard(build_target)
-    except (portage_util.MissingOverlayError, sysroot.Error):
-      cros_build_lib.Die('setup_board with default specifications failed. '
-                         "Please configure the board's sysroot separately.")
-
-  config = _get_build_config(build_target)
-
-  with workon_helper.WorkonScope(build_target, config.workon):
-    extra_env = {'FW_NAME': fw_name} if fw_name else None
-    # Run the emerge command to build the packages. Don't raise an exception
-    # here if it fails so we can cros workon stop afterwords.
-    logging.info('Building the AP firmware packages.')
-    # Print command with --debug.
-    print_cmd = logging.getLogger(__name__).getEffectiveLevel() == logging.DEBUG
-    default_build_flags = [
-        '--deep', '--update', '--newuse', '--newrepo', '--jobs', '--verbose'
-    ]
-    result = cros_build_lib.run(
-        [build_target.get_command('emerge')] + default_build_flags +
-        list(config.build),
-        print_cmd=print_cmd,
-        check=False,
-        debug_level=logging.DEBUG,
-        dryrun=dry_run,
-        extra_env=extra_env)
-
-  if result.returncode:
-    # Now raise the emerge failure since we're done cleaning up.
-    raise BuildError('The emerge command failed. Run with --verbose or --debug '
-                     'to see the emerge output for details.')
-
-  logging.notice('AP firmware image for device %s was built successfully '
-                 'and is available at %s.',
-                 build_target.name, build_target.full_path())
-
-
-def deploy(build_target,
-           image,
-           device,
-           flashrom=False,
-           fast=False,
-           verbose=False,
-           dryrun=False,
-           flash_contents: Optional[str] = None,
-           passthrough_args: Iterable[str] = tuple()):
-  """Deploy a firmware image to a device.
-
-  Args:
-    build_target (build_target_lib.BuildTarget): The build target.
-    image (str): The path to the image to flash.
-    device (commandline.Device): The DUT being flashed.
-    flashrom (bool): Whether to use flashrom or futility.
-    fast (bool): Perform a faster flash that isn't validated.
-    verbose (bool): Whether to enable verbose output of the flash commands.
-    dryrun (bool): Whether to actually execute the deployment or just print the
-      operations that would have been performed.
-    flash_contents: Path to the file that contains the existing contents.
-    passthrough_args: List of additional options passed to flashrom or futility.
-  """
-  try:
-    flash_ap.deploy(
-        build_target=build_target,
-        image=image,
-        device=device,
-        flashrom=flashrom,
-        fast=fast,
-        verbose=verbose,
-        dryrun=dryrun,
-        flash_contents=flash_contents,
-        passthrough_args=passthrough_args)
-  except flash_ap.Error as e:
-    # Reraise as a DeployError for future compatibility.
-    raise DeployError(str(e))
-
-
-class DeployConfig(object):
-  """Deploy configuration wrapper."""
-
-  FORCE_FLASHROM = 'flashrom'
-  FORCE_FUTILITY = 'futility'
-
-  def __init__(self,
-               get_config,
-               force_fast=None,
-               servo_force_command=None,
-               ssh_force_command=None):
-    """DeployConfig init.
-
-    Args:
-      get_config: A function that takes a servo and returns a
-        servo_lib.FirmwareConfig with settings to flash a servo
-        for a particular build target.
-      force_fast: A function that takes two arguments; a bool to indicate if it
-        is for a futility (True) or flashrom (False) command.
-      servo_force_command: One of the FORCE_{command} constants to force use of
-        a specific command, or None to not force.
-      ssh_force_command: One of the FORCE_{command} constants to force use of
-        a specific command, or None to not force.
-    """
-    self._get_config = get_config
-    self._force_fast = force_fast
-    self._servo_force_command = servo_force_command
-    self._ssh_force_command = ssh_force_command
-
-  @property
-  def servo_force_flashrom(self):
-    return self._servo_force_command == self.FORCE_FLASHROM
-
-  @property
-  def servo_force_futility(self):
-    return self._servo_force_command == self.FORCE_FUTILITY
-
-  @property
-  def ssh_force_flashrom(self):
-    return self._ssh_force_command == self.FORCE_FLASHROM
-
-  @property
-  def ssh_force_futility(self):
-    return self._ssh_force_command == self.FORCE_FUTILITY
-
-  def force_fast(self, servo, flashrom):
-    """Check if the fast flash option is required.
-
-    Some configurations fail flash verification, which can be skipped with
-    a fast flash.
-
-    Args:
-      servo (servo_lib.Servo): The servo connected to the DUT.
-      flashrom (bool): Whether flashrom is being used instead of futility.
-
-    Returns:
-      bool: True if it requires a fast flash, False otherwise.
-    """
-    if not self._force_fast:
-      # No function defined in the module, so no required cases.
-      return False
-
-    return self._force_fast(not flashrom, servo)
-
-  def get_servo_commands(self,
-                         servo,
-                         image_path,
-                         flashrom=False,
-                         fast=False,
-                         verbose=False):
-    """Get the servo flash commands from the build target config."""
-    ap_conf = self._get_config(servo)
-
-    # Make any forced changes to the given options.
-    if not flashrom and self.servo_force_flashrom:
-      logging.notice('Forcing flashrom flash.')
-      flashrom = True
-    elif flashrom and self.servo_force_futility:
-      logging.notice('Forcing futility flash.')
-      flashrom = False
-
-    if not fast and self.force_fast(servo, flashrom):
-      logging.notice('Forcing fast flash.')
-      fast = True
-
-    # Make common command additions here to simplify the config modules.
-    flashrom_cmd = ['flashrom', '-p', ap_conf.programmer, '-w', image_path]
-    futility_cmd = [
-        'futility',
-        'update',
-        '-p',
-        ap_conf.programmer,
-        '-i',
-        image_path,
-    ]
-    futility_cmd += ['--force', '--wp=0']
-
-    if fast:
-      flashrom_cmd += ['-n']
-      futility_cmd += ['--fast']
-    if verbose:
-      flashrom_cmd += ['-V']
-      futility_cmd += ['-v']
-
-    return ServoDeployCommands(
-        dut_on=ap_conf.dut_control_on,
-        dut_off=ap_conf.dut_control_off,
-        flash=flashrom_cmd if flashrom else futility_cmd)
-
-
-def _get_build_config(build_target):
-  """Get the relevant build config for |build_target|."""
-  module = get_config_module(build_target.name)
-  workon_pkgs = getattr(module, _CONFIG_BUILD_WORKON_PACKAGES, None)
-  build_pkgs = getattr(module, _CONFIG_BUILD_PACKAGES, None)
-
-  if not build_pkgs:
-    build_pkgs = ('chromeos-bootimage',)
-
-  return BuildConfig(workon=workon_pkgs, build=build_pkgs)
-
-
-def _get_deploy_config(build_target):
-  """Get the relevant deploy config for |build_target|."""
-  module = get_config_module(build_target.name)
-
-  # Get the force fast function if available.
-  force_fast = getattr(module, 'is_fast_required', None)
-
-  # Check the force servo command options.
-  servo_force = None
-  if getattr(module, 'DEPLOY_SERVO_FORCE_FLASHROM', False):
-    servo_force = DeployConfig.FORCE_FLASHROM
-  elif getattr(module, 'DEPLOY_SERVO_FORCE_FUTILITY', False):
-    servo_force = DeployConfig.FORCE_FUTILITY
-
-  # Check the force SSH command options.
-  ssh_force = None
-  if getattr(module, 'DEPLOY_SSH_FORCE_FLASHROM', False):
-    ssh_force = DeployConfig.FORCE_FLASHROM
-  elif getattr(module, 'DEPLOY_SSH_FORCE_FUTILITY', False):
-    ssh_force = DeployConfig.FORCE_FUTILITY
-
-  return DeployConfig(
-      module.get_config,
-      force_fast=force_fast,
-      servo_force_command=servo_force,
-      ssh_force_command=ssh_force)
-
-
-def get_config_module(build_target_name, disable_fallback=False):
-  """Return configuration module for a given build target.
-
-  Args:
-    build_target_name: Name of the build target, e.g. 'dedede'.
-    disable_fallback: Disables falling back to generic config if the config for
-                      build_target_name is not found.
-
-  Returns:
-    module: Python configuration module for a given build target.
-  """
-  name = _BUILD_TARGET_CONFIG_MODULE % build_target_name
-  try:
-    return importlib.import_module(name)
-  except ImportError:
-    name_path = name.replace('.', '/') + '.py'
-    if disable_fallback:
-      raise BuildTargetNotConfiguredError(
-          f'Could not find a config module for {build_target_name}. '
-          f'Fill in the config in {name_path}.')
-  # Failling back to generic config.
-  logging.notice(
-      'Did not find a dedicated config module for %s at %s. '
-      'Using default config.', build_target_name, name_path)
-  name = _BUILD_TARGET_CONFIG_MODULE % _GENERIC_CONFIG_NAME
-  try:
-    return importlib.import_module(name)
-  except ImportError:
-    name_path = name.replace('.', '/') + '.py'
-    if disable_fallback:
-      raise BuildTargetNotConfiguredError(
-          f'Could not find a generic config module at {name_path}. '
-          'Is your checkout broken?')
-
-
-def clean(build_target: build_target_lib.BuildTarget, dry_run=False):
-  """Cleans packages and dependencies related to a specified target.
-
-  After running the command, the user's environment should be able to
-  successfully build packages for a target board.
-
-  Args:
-    build_target: Target board to be cleaned
-    dry_run: Indicates that packages and system files should not be modified
-  """
-  pkgs = []
-  try:
-    qfile_pkgs = cros_build_lib.run([build_target.get_command('qfile'),
-                                     '/firmware'], capture_output=True,
-                                    check=False, dryrun=dry_run).stdout
-    pkgs = [l.split()[0] for l in qfile_pkgs.decode().splitlines()]
-  except cros_build_lib.RunCommandError as e:
-    raise CleanError('qfile for target board %s is not present; board may '
-                     'not have been set up.' % build_target.name)
-
-  try:
-    config = _get_build_config(build_target)
-    pkgs = set(pkgs).union(config.build)
-  except InvalidConfigError:
-    pass
-  pkgs = sorted(set(pkgs).union(['coreboot-private-files',
-                                 'chromeos-config-bsp']))
-
-  err = []
-  try:
-    cros_build_lib.run([build_target.get_command('emerge'), '--rage-clean',
-                        *pkgs], capture_output=True, dryrun=dry_run)
-  except cros_build_lib.RunCommandError as e:
-    err.append(e)
-
-  try:
-    if dry_run:
-      logging.notice('rm -rf -- /build/%s/firmware/*', build_target.name)
-    else:
-      osutils.RmDir('/build/%s/firmware/*' % build_target.name, sudo=True,
-                    ignore_missing=True)
-  except (EnvironmentError, cros_build_lib.RunCommandError) as e:
-    err.append(e)
-
-  if err:
-    logging.warning('All processes for %s have completed, but some were '
-                    'completed with errors.', build_target.name)
-    for e in err:
-      logging.error(e)
-    raise CleanError("`cros ap clean -b %s' did not complete successfully."
-                     % build_target.name)
-
-  logging.notice('AP firmware image for device %s was successfully cleaned.'
-                 '\nThe following packages were unmerged: %s'
-                 '\nThe following build target directory was removed: '
-                 '/build/%s/firmware', build_target.name, ' '.join(pkgs),
-                 build_target.name)
diff --git a/lib/firmware/ap_firmware_config/README.md b/lib/firmware/ap_firmware_config/README.md
new file mode 100644
index 0000000..aa24ecc
--- /dev/null
+++ b/lib/firmware/ap_firmware_config/README.md
@@ -0,0 +1,75 @@
+# AP Firmware tooling configuration guide:
+
+This guide covers how to write configuration files for `cros ap` tooling.
+If you're interested in `cros ap` tooling usage guide, please refer to
+[../README.md](../README.md)
+
+Note that it is not necessarily required to write custom config for your board.
+If config for your board is missing, [generic config](generic.py) will be used,
+and it should work in most cases.
+
+## Add support for a new board
+
+Create `${BOARD}.py` in `chromite/lib/firmware/ap_firmware_config`.
+Generic config [`generic.py`](generic.py) file can be copied into place,
+and used as a starting point for your config.
+
+### Variables to define
+
+#### Force flashrom for ssh/servo flashing
+By default, `cros ap flash` will flash with `futility`.
+If `futility` works for your board, there's no need to define any variables.
+If there's a reason to use `flashrom` instead for SSH/Servo flashing,
+set either of the following variables to true.
+
+```
+DEPLOY_SSH_FORCE_FLASHROM = True
+DEPLOY_SERVO_FORCE_FLASHROM = True
+```
+
+### Functions to define:
+#### Extra flags to use when flashing with futility/flashrom
+You can use `deploy_extra_flags_futility` and `deploy_extra_flags_flashrom` functions to add extra flags(such as --fast or --force) to
+futility and flashrom respectively while flashing.
+These functions accept [`servo_lib.Servo` object](https://source.corp.google.com/chromeos_public/chromite/lib/firmware/servo_lib.py) (or `None` for SSH) and return a list of flags.
+
+```
+def deploy_extra_flags_futility(servo: Optional[servo_lib.Servo]) -> List[str]
+```
+```
+def deploy_extra_flags_flashrom(servo: Optional[servo_lib.Servo]) -> List[str]
+```
+
+#### ServoConfig
+`get_config` is the primary function to set config for flashing with Servo.
+It accepts [`servo_lib.Servo` object](https://source.corp.google.com/chromeos_public/chromite/lib/firmware/servo_lib.py) and returns a [`servo_lib.ServoConfig` tuple](https://source.corp.google.com/chromeos_public/chromite/lib/firmware/servo_lib.py), which contains dut_control commands to be run before and after flashing, and programmer argument to be used for flashing.
+```
+def get_config(servo: servo_lib.Servo) -> servo_lib.ServoConfig
+```
+
+## Deprecated
+You shouldn't use any of those:
+ * BUILD_PACKAGES and BUILD_WORKON_PACKAGES are not needed anymore.
+ * `is_fast_required()` should be specified as part of `deploy_extra_flags_futility()` or `deploy_extra_flags_flashrom()` (see above)
+
+### Deprecated variables
+
+```
+    BUILD_WORKON_PACKAGES as a list of all packages that should be cros_workon'd
+      before building.
+
+    BUILD_PACKAGES as a list of all packages that should be emerged during the
+      build process.
+```
+### Deprecated functions
+```
+    is_fast_required:
+      Only required if it needs to return True for any cases!
+      Returns true if --fast is necessary to flash successfully.
+
+      Args:
+        use_futility (bool): True if futility is to be used, False if flashrom.
+        servo (str): The type name of the servo device being used.
+      Returns:
+        bool: True if fast is necessary, False otherwise.
+```
diff --git a/lib/firmware/ap_firmware_config/__init__.py b/lib/firmware/ap_firmware_config/__init__.py
index e69de29..3d9e22d 100644
--- a/lib/firmware/ap_firmware_config/__init__.py
+++ b/lib/firmware/ap_firmware_config/__init__.py
@@ -0,0 +1,61 @@
+# Copyright 2021 The Chromium OS 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 importlib
+import importlib.util
+import logging
+import pkgutil
+from types import ModuleType
+from typing import Iterator, Tuple
+
+_CONFIG_MODULE_FULL_NAME = 'chromite.lib.firmware.ap_firmware_config.%s'
+_GENERIC_CONFIG_NAME = 'generic'
+
+
+class Error(Exception):
+  """Base error class for the module."""
+
+
+class BuildTargetNotConfiguredError(Error):
+  """Thrown when a config module does not exist for the build target."""
+
+
+def configs() -> Iterator[Tuple[str, ModuleType]]:
+  """Iterate over all config modules.
+
+  Yields:
+    (board, module): build target name and associated config module.
+  """
+  for _, module_name, _ in pkgutil.iter_modules(__path__):
+    if module_name.startswith('_'):
+      continue
+    yield module_name, get(module_name, fallback=False)
+
+
+def get(build_target_name: str, fallback: bool = True) -> ModuleType:
+  """Return configuration module for a given build target.
+
+  Args:
+    build_target_name: Name of the build target, e.g. 'dedede'.
+    fallback: Allows falling back to generic config if the config for
+              build_target_name is not found.
+
+  Returns:
+    module: Python configuration module for a given build target.
+  """
+  name = _CONFIG_MODULE_FULL_NAME % build_target_name
+  try:
+    return importlib.import_module(name)
+  except ImportError:
+    name_path = name.replace('.', '/') + '.py'
+    if not fallback:
+      raise BuildTargetNotConfiguredError(
+          f'Could not find a config module for {build_target_name}. '
+          f'Fill in the config in {name_path}.')
+
+  # Falling back to generic config.
+  logging.notice(
+      'Did not find a dedicated config module for %s at %s. '
+      'Using default config.', build_target_name, name_path)
+  return get(_GENERIC_CONFIG_NAME, fallback=False)
diff --git a/lib/firmware/ap_firmware_config/brya.py b/lib/firmware/ap_firmware_config/brya.py
index b21a090..4d9e905 100644
--- a/lib/firmware/ap_firmware_config/brya.py
+++ b/lib/firmware/ap_firmware_config/brya.py
@@ -15,8 +15,7 @@
 )
 
 BUILD_WORKON_PACKAGES = _COMMON_PACKAGES + (
-    'coreboot-private-files-baseboard-brya',
-)
+    'coreboot-private-files-baseboard-brya',)
 
 BUILD_PACKAGES = _COMMON_PACKAGES + (
     'chromeos-bootimage',
@@ -25,11 +24,11 @@
 )
 
 
-def get_config(servo: servo_lib.Servo) -> servo_lib.FirmwareConfig:
-  """Get specific flash config for Brya.
+def get_config(servo: servo_lib.Servo) -> servo_lib.ServoConfig:
+  """Get DUT controls and programmer argument to flash Brya.
 
   Each board needs specific config including the voltage for Vref, to turn
-  on and turn off the SPI flash. get_config() returns servo_lib.FirmwareConfig
+  on and turn off the SPI flash. get_config() returns servo_lib.ServoConfig
   with settings to flash a servo for a particular build target.
   The voltage for this board needs to be set to 3.3 V.
 
@@ -37,7 +36,7 @@
     servo: The servo connected to the target DUT.
 
   Returns:
-    servo_lib.FirmwareConfig:
+    servo_lib.ServoConfig:
       dut_control_{on, off}=2d arrays formatted like [["cmd1", "arg1", "arg2"],
                                                       ["cmd2", "arg3", "arg4"]]
                             where cmd1 will be run before cmd2.
@@ -66,4 +65,4 @@
     raise servo_lib.UnsupportedServoVersionError('%s not supported' %
                                                  servo.version)
 
-  return servo_lib.FirmwareConfig(dut_control_on, dut_control_off, programmer)
+  return servo_lib.ServoConfig(dut_control_on, dut_control_off, programmer)
diff --git a/lib/firmware/ap_firmware_config/dedede.py b/lib/firmware/ap_firmware_config/dedede.py
index a79734b..e056a31 100644
--- a/lib/firmware/ap_firmware_config/dedede.py
+++ b/lib/firmware/ap_firmware_config/dedede.py
@@ -15,8 +15,7 @@
 )
 
 BUILD_WORKON_PACKAGES = _COMMON_PACKAGES + (
-    'coreboot-private-files-baseboard-dedede',
-)
+    'coreboot-private-files-baseboard-dedede',)
 
 BUILD_PACKAGES = _COMMON_PACKAGES + (
     'chromeos-bootimage',
@@ -25,11 +24,11 @@
 )
 
 
-def get_config(servo: servo_lib.Servo) -> servo_lib.FirmwareConfig:
-  """Get specific flash config for Dedede.
+def get_config(servo: servo_lib.Servo) -> servo_lib.ServoConfig:
+  """Get DUT controls and programmer argument to flash Dedede.
 
   Each board needs specific config including the voltage for Vref, to turn
-  on and turn off the SPI flash. get_config() returns servo_lib.FirmwareConfig
+  on and turn off the SPI flash. get_config() returns servo_lib.ServoConfig
   with settings to flash a servo for a particular build target.
   The voltage for this board needs to be set to 3.3 V.
 
@@ -37,7 +36,7 @@
     servo: The servo connected to the target DUT.
 
   Returns:
-    servo_lib.FirmwareConfig:
+    servo_lib.ServoConfig:
       dut_control_{on, off}=2d arrays formatted like [["cmd1", "arg1", "arg2"],
                                                       ["cmd2", "arg3", "arg4"]]
                             where cmd1 will be run before cmd2.
@@ -75,4 +74,4 @@
     raise servo_lib.UnsupportedServoVersionError('%s not supported' %
                                                  servo.version)
 
-  return servo_lib.FirmwareConfig(dut_control_on, dut_control_off, programmer)
+  return servo_lib.ServoConfig(dut_control_on, dut_control_off, programmer)
diff --git a/lib/firmware/ap_firmware_config/eve.py b/lib/firmware/ap_firmware_config/eve.py
index a6aefca..ab58146 100644
--- a/lib/firmware/ap_firmware_config/eve.py
+++ b/lib/firmware/ap_firmware_config/eve.py
@@ -7,21 +7,22 @@
 from chromite.lib.firmware import servo_lib
 
 BUILD_WORKON_PACKAGES = (
-  'chromeos-mrc',
-  'coreboot',
+    'chromeos-mrc',
+    'coreboot',
 )
 
 BUILD_PACKAGES = BUILD_WORKON_PACKAGES + (
-  'coreboot-private-files-eve',
-  'depthcharge',
-  'chromeos-bootimage',
+    'coreboot-private-files-eve',
+    'depthcharge',
+    'chromeos-bootimage',
 )
 
-def get_config(servo: servo_lib.Servo) -> servo_lib.FirmwareConfig:
-  """Get specific flash config for eve.
+
+def get_config(servo: servo_lib.Servo) -> servo_lib.ServoConfig:
+  """Get DUT controls and programmer argument to flash eve.
 
   Each board needs specific config including the voltage for Vref, to turn
-  on and turn off the SPI flash. get_config() returns servo_lib.FirmwareConfig
+  on and turn off the SPI flash. get_config() returns servo_lib.ServoConfig
   with settings to flash a servo for a particular build target.
   The voltage for this board needs to be set to 3.3 V.
 
@@ -29,7 +30,7 @@
     servo: The servo connected to the target DUT.
 
   Returns:
-    servo_lib.FirmwareConfig:
+    servo_lib.ServoConfig:
       dut_control_{on, off}=2d arrays formatted like [["cmd1", "arg1", "arg2"],
                                                       ["cmd2", "arg3", "arg4"]]
                             where cmd1 will be run before cmd2.
@@ -43,4 +44,4 @@
     raise servo_lib.UnsupportedServoVersionError('%s not supported' %
                                                  servo.version)
 
-  return servo_lib.FirmwareConfig(dut_control_on, dut_control_off, programmer)
+  return servo_lib.ServoConfig(dut_control_on, dut_control_off, programmer)
diff --git a/lib/firmware/ap_firmware_config/generic.py b/lib/firmware/ap_firmware_config/generic.py
index ce1ca3f..0e0a3a5 100644
--- a/lib/firmware/ap_firmware_config/generic.py
+++ b/lib/firmware/ap_firmware_config/generic.py
@@ -5,6 +5,7 @@
 # TODO: Name the build target.
 
 """{Build Target} configs."""
+from typing import List, Optional
 
 from chromite.lib.firmware import servo_lib
 
@@ -29,22 +30,47 @@
 # DEPLOY_SERVO_FORCE_FLASHROM = False
 
 
-# pylint: disable=unused-argument
-def deploy_extra_flags_futility(servo: servo_lib.Servo) -> str:
-  """Returns extra flags for flashing with futility"""
-  return ''
+def deploy_extra_flags_futility(servo: Optional[servo_lib.Servo]) -> List[str]:
+  """Returns extra flags for flashing with futility.
+
+  Args:
+    servo: The servo connected to the target DUT. Return flags for ssh if None.
+
+  Returns:
+    extra_flags: List of extra flags.
+  """
+  if not servo:
+    # extra flags for flashing with futility directly over ssh
+    return []
+  if servo.is_ccd:
+    # when flashing over CCD, skip verify step
+    return ['--fast']
+  return []
 
 
-def deploy_extra_flags_flashrom(servo: servo_lib.Servo) -> str:
-  """Returns extra flags for flashing with flashrom"""
-  return ''
+def deploy_extra_flags_flashrom(servo: Optional[servo_lib.Servo]) -> List[str]:
+  """Returns extra flags for flashing with flashrom.
+
+  Args:
+    servo: The servo connected to the target DUT. Return flags for ssh if None.
+
+  Returns:
+    extra_flags: List of extra flags.
+  """
+  if not servo:
+    # extra flags for flashing with flashrom directly over ssh
+    return []
+  if servo.is_ccd:
+    # when flashing over CCD, skip verify step
+    return ['-n']
+  return []
 
 
-def get_config(servo: servo_lib.Servo) -> servo_lib.FirmwareConfig:
-  """Get specific flash config for the build target.
+def get_config(servo: servo_lib.Servo) -> servo_lib.ServoConfig:
+  """Get DUT controls and programmer argument to flash a build target.
 
   Each board needs specific config including the voltage for Vref, to turn
-  on and turn off the SPI flash. get_config() returns servo_lib.FirmwareConfig
+  on and turn off the SPI flash. get_config() returns servo_lib.ServoConfig
   with settings to flash a servo for a particular build target.
   The voltage for this board needs to be set to 1.8 V.
 
@@ -52,7 +78,7 @@
     servo: The servo connected to the target DUT.
 
   Returns:
-    servo_lib.FirmwareConfig:
+    servo_lib.ServoConfig:
       dut_control_{on, off}=2d arrays formatted like [["cmd1", "arg1", "arg2"],
                                                       ["cmd2", "arg3", "arg4"]]
                             where cmd1 will be run before cmd2.
@@ -74,7 +100,7 @@
     raise servo_lib.UnsupportedServoVersionError('%s not supported' %
                                                  servo.version)
 
-  return servo_lib.FirmwareConfig(dut_control_on, dut_control_off, programmer)
+  return servo_lib.ServoConfig(dut_control_on, dut_control_off, programmer)
 
 
 # End FLASH CONFIGS.
diff --git a/lib/firmware/ap_firmware_config/grunt.py b/lib/firmware/ap_firmware_config/grunt.py
index fdaa123..fd460a5 100644
--- a/lib/firmware/ap_firmware_config/grunt.py
+++ b/lib/firmware/ap_firmware_config/grunt.py
@@ -25,11 +25,11 @@
   return use_futility and servo.is_v4
 
 
-def get_config(servo: servo_lib.Servo) -> servo_lib.FirmwareConfig:
-  """Get specific flash config for the grunt.
+def get_config(servo: servo_lib.Servo) -> servo_lib.ServoConfig:
+  """Get DUT controls and programmer argument to flash the grunt.
 
   Each board needs specific config including the voltage for Vref, to turn
-  on and turn off the SPI flash. get_config() returns servo_lib.FirmwareConfig
+  on and turn off the SPI flash. get_config() returns servo_lib.ServoConfig
   with settings to flash a servo for a particular build target.
   The voltage for this board needs to be set to 1.8 V.
 
@@ -37,7 +37,7 @@
     servo: The servo connected to the target DUT.
 
   Returns:
-    servo_lib.FirmwareConfig:
+    servo_lib.ServoConfig:
       dut_control_{on, off}=2d arrays formatted like [["cmd1", "arg1", "arg2"],
                                                       ["cmd2", "arg3", "arg4"]]
                             where cmd1 will be run before cmd2.
@@ -71,4 +71,4 @@
     raise servo_lib.UnsupportedServoVersionError('%s not supported' %
                                                  servo.version)
 
-  return servo_lib.FirmwareConfig(dut_control_on, dut_control_off, programmer)
+  return servo_lib.ServoConfig(dut_control_on, dut_control_off, programmer)
diff --git a/lib/firmware/ap_firmware_config/guybrush.py b/lib/firmware/ap_firmware_config/guybrush.py
index 7eec4e3..6859215 100644
--- a/lib/firmware/ap_firmware_config/guybrush.py
+++ b/lib/firmware/ap_firmware_config/guybrush.py
@@ -19,11 +19,11 @@
 )
 
 
-def get_config(servo: servo_lib.Servo) -> servo_lib.FirmwareConfig:
-  """Get specific flash config for Guybrush.
+def get_config(servo: servo_lib.Servo) -> servo_lib.ServoConfig:
+  """Get DUT controls and programmer argument to flash Guybrush.
 
   Each board needs specific config including the voltage for Vref, to turn
-  on and turn off the SPI flash. get_config() returns servo_lib.FirmwareConfig
+  on and turn off the SPI flash. get_config() returns servo_lib.ServoConfig
   with settings to flash a servo for a particular build target.
   The voltage for this board needs to be set to 1.8 V.
 
@@ -31,7 +31,7 @@
     servo: The servo connected to the target DUT.
 
   Returns:
-    servo_lib.FirmwareConfig:
+    servo_lib.ServoConfig:
       dut_control_{on, off}=2d arrays formatted like [["cmd1", "arg1", "arg2"],
                                                       ["cmd2", "arg3", "arg4"]]
                             where cmd1 will be run before cmd2.
@@ -79,4 +79,4 @@
     raise servo_lib.UnsupportedServoVersionError('%s not supported' %
                                                  servo.version)
 
-  return servo_lib.FirmwareConfig(dut_control_on, dut_control_off, programmer)
+  return servo_lib.ServoConfig(dut_control_on, dut_control_off, programmer)
diff --git a/lib/firmware/ap_firmware_config/hatch.py b/lib/firmware/ap_firmware_config/hatch.py
index 937c15a..9866a9e 100644
--- a/lib/firmware/ap_firmware_config/hatch.py
+++ b/lib/firmware/ap_firmware_config/hatch.py
@@ -22,11 +22,11 @@
 )
 
 
-def get_config(servo: servo_lib.Servo) -> servo_lib.FirmwareConfig:
-  """Get specific flash config for hatch.
+def get_config(servo: servo_lib.Servo) -> servo_lib.ServoConfig:
+  """Get DUT controls and programmer argument to flash hatch.
 
   Each board needs specific config including the voltage for Vref, to turn
-  on and turn off the SPI flash. get_config() returns servo_lib.FirmwareConfig
+  on and turn off the SPI flash. get_config() returns servo_lib.ServoConfig
   with settings to flash a servo for a particular build target.
   The voltage for this board needs to be set to 3.3 V.
 
@@ -34,7 +34,7 @@
     servo: The servo connected to the target DUT.
 
   Returns:
-    servo_lib.FirmwareConfig:
+    servo_lib.ServoConfig:
       dut_control_{on, off}=2d arrays formatted like [["cmd1", "arg1", "arg2"],
                                                       ["cmd2", "arg3", "arg4"]]
                             where cmd1 will be run before cmd2.
@@ -81,4 +81,4 @@
     raise servo_lib.UnsupportedServoVersionError('%s not supported' %
                                                  servo.version)
 
-  return servo_lib.FirmwareConfig(dut_control_on, dut_control_off, programmer)
+  return servo_lib.ServoConfig(dut_control_on, dut_control_off, programmer)
diff --git a/lib/firmware/ap_firmware_config/keeby.py b/lib/firmware/ap_firmware_config/keeby.py
index 0194bf0..a119e66 100644
--- a/lib/firmware/ap_firmware_config/keeby.py
+++ b/lib/firmware/ap_firmware_config/keeby.py
@@ -21,11 +21,11 @@
 )
 
 
-def get_config(servo: servo_lib.Servo) -> servo_lib.FirmwareConfig:
-  """Get specific flash config for Keeby.
+def get_config(servo: servo_lib.Servo) -> servo_lib.ServoConfig:
+  """Get DUT controls and programmer argument to flash Keeby.
 
   Each board needs specific config including the voltage for Vref, to turn
-  on and turn off the SPI flash. get_config() returns servo_lib.FirmwareConfig
+  on and turn off the SPI flash. get_config() returns servo_lib.ServoConfig
   with settings to flash a servo for a particular build target.
   The voltage for this board needs to be set to 3.3 V.
 
@@ -33,7 +33,7 @@
     servo: The servo connected to the target DUT.
 
   Returns:
-    servo_lib.FirmwareConfig:
+    servo_lib.ServoConfig:
       dut_control_{on, off}=2d arrays formatted like [["cmd1", "arg1", "arg2"],
                                                       ["cmd2", "arg3", "arg4"]]
                             where cmd1 will be run before cmd2.
@@ -70,4 +70,4 @@
     raise servo_lib.UnsupportedServoVersionError('%s not supported' %
                                                  servo.version)
 
-  return servo_lib.FirmwareConfig(dut_control_on, dut_control_off, programmer)
+  return servo_lib.ServoConfig(dut_control_on, dut_control_off, programmer)
diff --git a/lib/firmware/ap_firmware_config/mancomb.py b/lib/firmware/ap_firmware_config/mancomb.py
index 200819d..0c86f52 100644
--- a/lib/firmware/ap_firmware_config/mancomb.py
+++ b/lib/firmware/ap_firmware_config/mancomb.py
@@ -22,11 +22,11 @@
 )
 
 
-def get_config(servo: servo_lib.Servo) -> servo_lib.FirmwareConfig:
-  """Get specific flash config for Mancomb.
+def get_config(servo: servo_lib.Servo) -> servo_lib.ServoConfig:
+  """Get DUT controls and programmer argument to flash Mancomb.
 
   Each board needs specific config including the voltage for Vref, to turn
-  on and turn off the SPI flash. get_config() returns servo_lib.FirmwareConfig
+  on and turn off the SPI flash. get_config() returns servo_lib.ServoConfig
   with settings to flash a servo for a particular build target.
   The voltage for this board needs to be set to 1.8 V.
 
@@ -34,7 +34,7 @@
     servo: The servo connected to the target DUT.
 
   Returns:
-    servo_lib.FirmwareConfig:
+    servo_lib.ServoConfig:
       dut_control_{on, off}=2d arrays formatted like [["cmd1", "arg1", "arg2"],
                                                       ["cmd2", "arg3", "arg4"]]
                             where cmd1 will be run before cmd2.
@@ -63,4 +63,4 @@
     raise servo_lib.UnsupportedServoVersionError('%s not supported' %
                                                  servo.version)
 
-  return servo_lib.FirmwareConfig(dut_control_on, dut_control_off, programmer)
+  return servo_lib.ServoConfig(dut_control_on, dut_control_off, programmer)
diff --git a/lib/firmware/ap_firmware_config/octopus.py b/lib/firmware/ap_firmware_config/octopus.py
index e61f98a..8602758 100644
--- a/lib/firmware/ap_firmware_config/octopus.py
+++ b/lib/firmware/ap_firmware_config/octopus.py
@@ -34,11 +34,11 @@
   return use_futility and servo.version == servo_lib.SERVO_V4_CCD
 
 
-def get_config(servo: servo_lib.Servo) -> servo_lib.FirmwareConfig:
-  """Get specific flash config for octopus.
+def get_config(servo: servo_lib.Servo) -> servo_lib.ServoConfig:
+  """Get DUT controls and programmer argument to flash octopus.
 
   Each board needs specific config including the voltage for Vref, to turn
-  on and turn off the SPI flash. get_config() returns servo_lib.FirmwareConfig
+  on and turn off the SPI flash. get_config() returns servo_lib.ServoConfig
   with settings to flash a servo for a particular build target.
   The voltage for this board needs to be set to 1.8 V.
 
@@ -46,7 +46,7 @@
     servo: The servo connected to the target DUT.
 
   Returns:
-    servo_lib.FirmwareConfig:
+    servo_lib.ServoConfig:
       dut_control_{on, off}=2d arrays formatted like [["cmd1", "arg1", "arg2"],
                                                       ["cmd2", "arg3", "arg4"]]
                             where cmd1 will be run before cmd2.
@@ -75,4 +75,4 @@
     raise servo_lib.UnsupportedServoVersionError('%s not supported' %
                                                  servo.version)
 
-  return servo_lib.FirmwareConfig(dut_control_on, dut_control_off, programmer)
+  return servo_lib.ServoConfig(dut_control_on, dut_control_off, programmer)
diff --git a/lib/firmware/ap_firmware_config/puff.py b/lib/firmware/ap_firmware_config/puff.py
index 0ae6432..475393b 100644
--- a/lib/firmware/ap_firmware_config/puff.py
+++ b/lib/firmware/ap_firmware_config/puff.py
@@ -22,11 +22,11 @@
 )
 
 
-def get_config(servo: servo_lib.Servo) -> servo_lib.FirmwareConfig:
-  """Get specific flash config for puff.
+def get_config(servo: servo_lib.Servo) -> servo_lib.ServoConfig:
+  """Get DUT controls and programmer argument to flash puff.
 
   Each board needs specific config including the voltage for Vref, to turn
-  on and turn off the SPI flash. get_config() returns servo_lib.FirmwareConfig
+  on and turn off the SPI flash. get_config() returns servo_lib.ServoConfig
   with settings to flash a servo for a particular build target.
   The voltage for this board needs to be set to 3.3 V.
 
@@ -34,7 +34,7 @@
     servo: The servo connected to the target DUT.
 
   Returns:
-    servo_lib.FirmwareConfig:
+    servo_lib.ServoConfig:
       dut_control_{on, off}=2d arrays formatted like [["cmd1", "arg1", "arg2"],
                                                       ["cmd2", "arg3", "arg4"]]
                             where cmd1 will be run before cmd2.
@@ -73,4 +73,4 @@
     raise servo_lib.UnsupportedServoVersionError('%s not supported' %
                                                  servo.version)
 
-  return servo_lib.FirmwareConfig(dut_control_on, dut_control_off, programmer)
+  return servo_lib.ServoConfig(dut_control_on, dut_control_off, programmer)
diff --git a/lib/firmware/ap_firmware_config/skyrim.py b/lib/firmware/ap_firmware_config/skyrim.py
new file mode 100644
index 0000000..fc6f82b
--- /dev/null
+++ b/lib/firmware/ap_firmware_config/skyrim.py
@@ -0,0 +1,82 @@
+# Copyright 2022 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Skyrim configs."""
+
+from chromite.lib.firmware import servo_lib
+
+BUILD_PACKAGES = (
+    'chromeos-ec',
+    'coreboot',
+    'depthcharge',
+    'libpayload',
+    'vboot_reference',
+    'chromeos-bootimage',
+    'coreboot-private-files-board',
+    'coreboot-private-files-chipset',
+    'amd-cezanne-fsp',
+)
+
+
+def get_config(servo: servo_lib.Servo) -> servo_lib.ServoConfig:
+  """Get DUT controls and programmer argument to flash Guybrush.
+
+  Each board needs specific config including the voltage for Vref, to turn
+  on and turn off the SPI flash. get_config() returns servo_lib.ServoConfig
+  with settings to flash a servo for a particular build target.
+  The voltage for this board needs to be set to 1.8 V.
+
+  Args:
+    servo: The servo connected to the target DUT.
+
+  Returns:
+    servo_lib.ServoConfig:
+      dut_control_{on, off}=2d arrays formatted like [["cmd1", "arg1", "arg2"],
+                                                      ["cmd2", "arg3", "arg4"]]
+                            where cmd1 will be run before cmd2.
+      programmer=programmer argument (-p) for flashrom and futility.
+  """
+  dut_control_on = []
+  dut_control_off = []
+
+  # Common flashing sequence for C2D2 and CCD
+  # Shutdown AP so that it enters G3 state.
+  dut_control_on.append(['ec_uart_cmd:apshutdown'])
+  # Sleep to ensure the SoC rails get chance to discharge enough.
+  dut_control_on.append(['sleep:5'])
+
+  if servo.is_c2d2:
+    # CPLD will actually require AP_FLASH_SELECT of 0 in flashing
+    dut_control_on.append(['ap_flash_select:off'])
+    dut_control_on.append(['spi2_vref:pp1800'])
+    dut_control_off.append(['spi2_vref:off'])
+    programmer = 'raiden_debug_spi:serial=%s' % servo.serial
+  elif servo.is_micro:
+    # Note servo micro is only supported for dauntless daughterboard for
+    # a limited time. Once Dauntless moves to MLB, there will be no 50-pin
+    # servo connector to attach servo micro to.
+    dut_control_on.append(['ec_uart_cmd:apshutdown'])
+    dut_control_on.append([
+        'spi2_vref:pp1800',
+        'spi2_buf_en:on',
+        'spi2_buf_on_flex_en:on',
+        'spi_hold:off',
+    ])
+    dut_control_off.append([
+        'spi2_vref:off',
+        'spi2_buf_en:off',
+        'spi2_buf_on_flex_en:off',
+        'spi_hold:off',
+    ])
+    dut_control_off.append(['ec_uart_cmd:powerb'])
+    programmer = 'raiden_debug_spi:serial=%s' % servo.serial
+  elif servo.is_ccd:
+    dut_control_off.append(['power_state:reset'])
+    programmer = ('raiden_debug_spi:target=AP,custom_rst=True,serial=%s' %
+                  servo.serial)
+  else:
+    raise servo_lib.UnsupportedServoVersionError('%s not supported' %
+                                                 servo.version)
+
+  return servo_lib.ServoConfig(dut_control_on, dut_control_off, programmer)
diff --git a/lib/firmware/ap_firmware_config/volteer.py b/lib/firmware/ap_firmware_config/volteer.py
index 5079f0e..ace4e32 100644
--- a/lib/firmware/ap_firmware_config/volteer.py
+++ b/lib/firmware/ap_firmware_config/volteer.py
@@ -8,7 +8,6 @@
 
 from chromite.lib.firmware import servo_lib
 
-
 BUILD_WORKON_PACKAGES = None
 
 BUILD_PACKAGES = ('chromeos-bootimage',)
@@ -17,11 +16,11 @@
 DEPLOY_SERVO_FORCE_FLASHROM = True
 
 
-def get_config(servo: servo_lib.Servo) -> servo_lib.FirmwareConfig:
-  """Get specific flash config for the Volteer.
+def get_config(servo: servo_lib.Servo) -> servo_lib.ServoConfig:
+  """Get DUT controls and programmer argument to flash the Volteer.
 
   Each board needs specific config including the voltage for Vref, to turn
-  on and turn off the SPI flash. get_config() returns servo_lib.FirmwareConfig
+  on and turn off the SPI flash. get_config() returns servo_lib.ServoConfig
   with settings to flash a servo for a particular build target.
   The voltage for this board needs to be set to 3.3 V.
 
@@ -29,7 +28,7 @@
     servo: The servo connected to the target DUT.
 
   Returns:
-    servo_lib.FirmwareConfig:
+    servo_lib.ServoConfig:
       dut_control_{on, off}=2d arrays formatted like [["cmd1", "arg1", "arg2"],
                                                       ["cmd2", "arg3", "arg4"]]
                             where cmd1 will be run before cmd2.
@@ -54,4 +53,4 @@
     raise servo_lib.UnsupportedServoVersionError('%s not supported' %
                                                  servo.version)
 
-  return servo_lib.FirmwareConfig(dut_control_on, dut_control_off, programmer)
+  return servo_lib.ServoConfig(dut_control_on, dut_control_off, programmer)
diff --git a/lib/firmware/ap_firmware_config/wilco.py b/lib/firmware/ap_firmware_config/wilco.py
index 0c2ff25..7b63d65 100644
--- a/lib/firmware/ap_firmware_config/wilco.py
+++ b/lib/firmware/ap_firmware_config/wilco.py
@@ -8,7 +8,6 @@
 
 from chromite.lib.firmware import servo_lib
 
-
 # TODO(b/143241417): Use futility anytime flashing over ssh to avoid failures.
 DEPLOY_SSH_FORCE_FUTILITY = True
 
@@ -32,11 +31,11 @@
   return servo.is_micro
 
 
-def get_config(servo: servo_lib.Servo) -> servo_lib.FirmwareConfig:
-  """Get specific flash config for wilco.
+def get_config(servo: servo_lib.Servo) -> servo_lib.ServoConfig:
+  """Get DUT controls and programmer argument to flash wilco.
 
   Each board needs specific config including the voltage for Vref, to turn
-  on and turn off the SPI flash. get_config() returns servo_lib.FirmwareConfig
+  on and turn off the SPI flash. get_config() returns servo_lib.ServoConfig
   with settings to flash a servo for a particular build target.
   The voltage for this board needs to be set to 3.3 V.
 
@@ -49,7 +48,7 @@
   drallion uses. If you see an error about “4 byte addressing” run the
   following commands to get a useable flashrom
 
-  cd ~/trunk/src/third_party/flashrom/
+  cd ~/chromiumos/src/third_party/flashrom/
   git co ff7778ab25d0b343e781cffc0e45f329ee69a5a8~1
   cros_workon --host start flashrom
   sudo emerge flashrom
@@ -58,7 +57,7 @@
     servo: The servo connected to the target DUT.
 
   Returns:
-    servo_lib.FirmwareConfig:
+    servo_lib.ServoConfig:
       dut_control_{on, off}=2d arrays formatted like [["cmd1", "arg1", "arg2"],
                                                       ["cmd2", "arg3", "arg4"]]
                             where cmd1 will be run before cmd2.
@@ -93,4 +92,4 @@
     raise servo_lib.UnsupportedServoVersionError('%s not supported' %
                                                  servo.version)
 
-  return servo_lib.FirmwareConfig(dut_control_on, dut_control_off, programmer)
+  return servo_lib.ServoConfig(dut_control_on, dut_control_off, programmer)
diff --git a/lib/firmware/ap_firmware_config/zork.py b/lib/firmware/ap_firmware_config/zork.py
index 46b82c8..dd8b567 100644
--- a/lib/firmware/ap_firmware_config/zork.py
+++ b/lib/firmware/ap_firmware_config/zork.py
@@ -11,11 +11,11 @@
 BUILD_PACKAGES = BUILD_WORKON_PACKAGES + ('chromeos-bootimage',)
 
 
-def get_config(servo: servo_lib.Servo) -> servo_lib.FirmwareConfig:
-  """Get specific flash config for Zork.
+def get_config(servo: servo_lib.Servo) -> servo_lib.ServoConfig:
+  """Get DUT controls and programmer argument to flash Zork.
 
   Each board needs specific config including the voltage for Vref, to turn
-  on and turn off the SPI flash. get_config() returns servo_lib.FirmwareConfig
+  on and turn off the SPI flash. get_config() returns servo_lib.ServoConfig
   with settings to flash a servo for a particular build target.
   The voltage for this board needs to be set to 1.8 V.
 
@@ -23,7 +23,7 @@
     servo: The servo connected to the target DUT.
 
   Returns:
-    servo_lib.FirmwareConfig:
+    servo_lib.ServoConfig:
       dut_control_{on, off}=2d arrays formatted like [["cmd1", "arg1", "arg2"],
                                                       ["cmd2", "arg3", "arg4"]]
                             where cmd1 will be run before cmd2.
@@ -69,4 +69,4 @@
     raise servo_lib.UnsupportedServoVersionError('%s not supported' %
                                                  servo.version)
 
-  return servo_lib.FirmwareConfig(dut_control_on, dut_control_off, programmer)
+  return servo_lib.ServoConfig(dut_control_on, dut_control_off, programmer)
diff --git a/lib/firmware/ap_firmware_unittest.py b/lib/firmware/ap_firmware_unittest.py
deleted file mode 100644
index bc6305a..0000000
--- a/lib/firmware/ap_firmware_unittest.py
+++ /dev/null
@@ -1,254 +0,0 @@
-# Copyright 2020 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Tests for the ap_firmware module."""
-
-from unittest import mock
-
-from chromite.lib import build_target_lib
-from chromite.lib import cros_build_lib
-from chromite.lib import cros_test_lib
-from chromite.lib import osutils
-from chromite.lib import workon_helper
-from chromite.lib.firmware import ap_firmware
-from chromite.lib.firmware import servo_lib
-from chromite.service import sysroot
-
-class BuildTest(cros_test_lib.RunCommandTestCase):
-  """Tests for building ap firmware."""
-
-  def test_valid_build_config(self):
-    """Test building of the build config object."""
-    module = mock.MagicMock(
-        BUILD_WORKON_PACKAGES=('pkg1', 'pkg2'), BUILD_PACKAGES=('pkg3', 'pkg4'))
-
-    self.PatchObject(ap_firmware, 'get_config_module', return_value=module)
-
-    # pylint: disable=protected-access
-    build_config = ap_firmware._get_build_config(
-        build_target_lib.BuildTarget('board'))
-
-    self.assertEqual(('pkg1', 'pkg2'), build_config.workon)
-    self.assertEqual(('pkg3', 'pkg4'), build_config.build)
-
-  def test_no_workon_config(self):
-    """Test building of the build config object with no workon packages."""
-    module = mock.MagicMock(
-        BUILD_WORKON_PACKAGES=None, BUILD_PACKAGES=('pkg3', 'pkg4'))
-
-    self.PatchObject(ap_firmware, 'get_config_module', return_value=module)
-
-    # pylint: disable=protected-access
-    build_config = ap_firmware._get_build_config(
-        build_target_lib.BuildTarget('board'))
-
-    self.assertFalse(build_config.workon)
-    self.assertEqual(('pkg3', 'pkg4'), build_config.build)
-
-  def test_build(self):
-    """Sanity checks the workon and command building functions properly."""
-    # Note: The workon helper handles looking up full category/package atom
-    # when just given package names.
-    build_pkgs = ('build1', 'build2')
-    workon_pkgs = ('workon1', 'workon2')
-    # Inconsequential pkgs + 1 we need.
-    existing_workons = ['cat/pkg1', 'cat/pkg2', 'cat/workon1']
-    existing_and_required = existing_workons + ['cat/workon2']
-
-    build_config = ap_firmware.BuildConfig(workon=workon_pkgs, build=build_pkgs)
-    build_target = build_target_lib.BuildTarget('board')
-
-    # Simulate starting the required workon packages. Return first the existing
-    # workon packages, then the ones we're starting plus the existing.
-    self.PatchObject(
-        workon_helper.WorkonHelper,
-        'ListAtoms',
-        side_effect=[existing_workons, existing_and_required])
-    # Start and stop workon patches for verifying calls.
-    self.PatchObject(workon_helper.WorkonScope, '__enter__')
-    self.PatchObject(workon_helper.WorkonScope, '__exit__')
-
-    # Patch the SetupBoard command.
-    self.PatchObject(sysroot, 'SetupBoard')
-
-    # Patch in the build config.
-    self.PatchObject(
-        ap_firmware, '_get_build_config', return_value=build_config)
-
-    ap_firmware.build(build_target, 'board-variant')
-
-    # Verify we try to build all the build packages, and that the FW_NAME envvar
-    # has been set.
-    self.rc.assertCommandContains(
-        list(build_pkgs), extra_env={'FW_NAME': 'board-variant'})
-
-
-class DeployConfigTest(cros_test_lib.TestCase):
-  """Test the deploy configuration class."""
-
-  def setUp(self):
-    self.servo = servo_lib.Servo(servo_lib.SERVO_C2D2, 'abc123')
-
-    # Expected dut commands and base flash commands.
-    self.expected_dut_on = [['dut_on']]
-    self.expected_dut_off = [['dut_off']]
-    programmer = ['programmer_arg']
-    # The get commands function returning the base commands.
-    config = servo_lib.FirmwareConfig(
-        self.expected_dut_on[:],
-        self.expected_dut_off[:],
-        programmer[:],
-    )
-    self.get_config = (lambda *args: config)
-
-    # The expected commands.
-    self.image = 'image'
-    self.expected_flashrom = ['flashrom', '-p', programmer, '-w', self.image]
-    self.expected_futility = [
-        'futility',
-        'update',
-        '-p',
-        programmer,
-        '-i',
-        self.image,
-    ]
-    # The optional fast and verbose arguments.
-    self.flashrom_fast_verbose = ['-n', '-V']
-    self.futility_fast_verbose = ['--fast', '-v']
-
-  def _assert_command(self, flash, flashrom=False, fast_verbose=None):
-    """Helper to check the flash command.
-
-    Args:
-      flash (list[str]): The command being checked.
-      flashrom (bool): Check flashrom (True) or futility (False).
-      fast_verbose (bool|None): Assert the fast and verbose options were (True)
-        or were not (False) added to the command, or skip the check (None).
-    """
-    # Base command checks.
-    expected = self.expected_flashrom if flashrom else self.expected_futility
-    for element in expected:
-      self.assertIn(element, flash)
-
-    # Fast/verbose checks.
-    expected = (
-        self.flashrom_fast_verbose if flashrom else self.futility_fast_verbose)
-    if fast_verbose:
-      for element in expected:
-        self.assertIn(element, flash)
-    elif fast_verbose is False:
-      for element in expected:
-        self.assertNotIn(element, flash)
-
-  def test_force_fast(self):
-    """Test the force fast call-through."""
-    force_fast = lambda futility, servo: futility and servo == self.servo
-
-    config = ap_firmware.DeployConfig(self.get_config, force_fast=force_fast)
-    self.assertTrue(config.force_fast(flashrom=False, servo=self.servo))
-    self.assertFalse(config.force_fast(flashrom=True, servo=self.servo))
-
-  def test_no_force_fast(self):
-    """Sanity check no force fast function gets handled properly."""
-    config = ap_firmware.DeployConfig(self.get_config)
-    self.assertFalse(config.force_fast(flashrom=False, servo=self.servo))
-    self.assertFalse(config.force_fast(flashrom=True, servo=self.servo))
-
-  def test_dut_commands(self):
-    """Sanity check for the dut commands pass through."""
-    config = ap_firmware.DeployConfig(self.get_config)
-    commands = config.get_servo_commands(self.servo, self.image)
-
-    self.assertListEqual(self.expected_dut_on, commands.dut_on)
-    self.assertListEqual(self.expected_dut_off, commands.dut_off)
-
-  def test_flashrom_command(self):
-    """Test the base flashrom command is built correctly."""
-    config = ap_firmware.DeployConfig(self.get_config)
-    commands = config.get_servo_commands(self.servo, self.image, flashrom=True)
-
-    self._assert_command(commands.flash, flashrom=True, fast_verbose=False)
-
-  def test_fast_verbose_flashrom(self):
-    """Sanity check the fast/verbose flashrom arguments get added."""
-    config = ap_firmware.DeployConfig(self.get_config)
-    commands = config.get_servo_commands(
-        self.servo, self.image, flashrom=True, fast=True, verbose=True)
-
-    self._assert_command(commands.flash, flashrom=True, fast_verbose=True)
-
-  def test_futility_command(self):
-    """Test the futility command is built correctly."""
-    config = ap_firmware.DeployConfig(self.get_config)
-    commands = config.get_servo_commands(self.servo, self.image)
-
-    self._assert_command(commands.flash, flashrom=False, fast_verbose=False)
-
-  def test_fast_verbose_futility(self):
-    """Sanity check the fast/verbose futility arguments get added."""
-    config = ap_firmware.DeployConfig(self.get_config)
-    commands = config.get_servo_commands(
-        self.servo, self.image, fast=True, verbose=True)
-
-    self._assert_command(commands.flash, flashrom=False, fast_verbose=True)
-
-  def test_force_fast_flashrom(self):
-    """Test the flashrom and fast command alterations."""
-    force_fast = lambda *args: True
-    config = ap_firmware.DeployConfig(
-        self.get_config,
-        force_fast=force_fast,
-        servo_force_command=ap_firmware.DeployConfig.FORCE_FLASHROM)
-
-    commands = config.get_servo_commands(self.servo, self.image, verbose=True)
-    self._assert_command(commands.flash, flashrom=True, fast_verbose=True)
-
-  def test_force_fast_futility(self):
-    """Test the futility and fast command alterations."""
-    force_fast = lambda *args: True
-    config = ap_firmware.DeployConfig(
-        self.get_config,
-        force_fast=force_fast,
-        servo_force_command=ap_firmware.DeployConfig.FORCE_FUTILITY)
-
-    commands = config.get_servo_commands(self.servo, self.image, verbose=True)
-    self._assert_command(commands.flash, flashrom=False, fast_verbose=True)
-
-class CleanTest(cros_test_lib.RunCommandTestCase):
-  """Tests for cleaning up firmware artifacts and dependencies."""
-
-  def setUp(self):
-    self.pkgs = ['pkg1', 'pkg2', 'coreboot-private-files',
-                 'chromeos-config-bsp']
-
-  def test_clean(self):
-    """Sanity check for the clean command (ideal case)."""
-    module = mock.MagicMock(
-        BUILD_WORKON_PACKAGES=None, BUILD_PACKAGES=('pkg3', 'pkg4'))
-
-    self.PatchObject(ap_firmware, 'get_config_module', return_value=module)
-
-    pkgs = [*self.pkgs, *module.BUILD_PACKAGES]
-
-    def run_side_effect(*args, **kwargs):
-      if args[0][0].startswith('qfile'):
-        if kwargs.get('capture_output'):
-          return mock.MagicMock(stdout='\n'.join(pkgs).encode())
-        return mock.MagicMock(stdout=''.encode())
-      elif args[0][0].startswith('emerge'):
-        return mock.MagicMock(returncode=0)
-
-    run_mock = self.PatchObject(cros_build_lib, 'run',
-                                side_effect=run_side_effect)
-    self.PatchObject(osutils, 'RmDir')
-    ap_firmware.clean(build_target_lib.BuildTarget('boardname'))
-    run_mock.assert_any_call([mock.ANY, mock.ANY, *sorted(pkgs)],
-                             capture_output=mock.ANY, dryrun=False)
-
-  def test_nonexistent_board_clean(self):
-    """Verifies exception thrown when target board was not configured."""
-    se = cros_build_lib.RunCommandError('nonexistent board')
-    self.PatchObject(cros_build_lib, 'run', side_effect=se)
-    with self.assertRaisesRegex(ap_firmware.CleanError, 'qfile'):
-      ap_firmware.clean(build_target_lib.BuildTarget('schrodinger'))
diff --git a/lib/firmware/dut.py b/lib/firmware/dut.py
new file mode 100644
index 0000000..6cb5a15
--- /dev/null
+++ b/lib/firmware/dut.py
@@ -0,0 +1,131 @@
+# Copyright 2021 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Utilities to run DUT Control commands, get values from Servo."""
+
+import logging
+import time
+
+from chromite.lib import cros_build_lib
+from chromite.lib.firmware import servo_lib
+
+
+class Error(Exception):
+  """Base error class for the module."""
+
+
+class InvalidServoVersionError(Error):
+  """Invalid servo version error."""
+
+
+class DutConnectionError(Error):
+  """Error when fetching data from a dut."""
+
+
+class DutControl():
+  """Wrapper for dut_control calls."""
+
+  def __init__(self, port):
+    self._base_cmd = ['dut-control']
+    if port:
+      self._base_cmd.append('--port=%s' % port)
+
+  def get_servo(self) -> servo_lib.Servo:
+    """Get the Servo instance the given dut_control command is using."""
+    servo_type = self.get_value('servo_type')
+
+    if '_and_' in servo_type:
+      # If servod is working with multiple interfaces then servo_type will be
+      # along the lines of "servo_v4p1_with_servo_micro_and_ccd_cr50".
+      # We need to pick an interface, so grab everything before "_and_".
+      first_servo_type = servo_type.split('_and_')[0]
+      logging.warning('Dual-mode servo detected. Treating %s as %s',
+                      servo_type, first_servo_type)
+      servo_type = first_servo_type
+
+    if servo_type not in servo_lib.VALID_SERVOS:
+      raise InvalidServoVersionError('Unrecognized servo version: %s' %
+                                     servo_type)
+
+    option = servo_lib.get_serial_option(servo_type)
+    serial = self.get_value(option)
+    return servo_lib.Servo(servo_type, serial)
+
+  def get_value(self, arg):
+    """Get the value of |arg| from dut_control."""
+    try:
+      result = cros_build_lib.run(
+          self._base_cmd + [arg], stdout=True, encoding='utf-8')
+    except cros_build_lib.CalledProcessError as e:
+      logging.debug('dut-control error: %s', str(e))
+      raise DutConnectionError(
+          'Could not establish servo connection. Verify servod is running in '
+          'the background, and the servo is properly connected.')
+
+    # Return value from the "key:value" output.
+    return result.stdout.partition(':')[2].strip()
+
+  def run(self, cmd_fragment, verbose=False, dryrun=False):
+    """Run a dut_control command.
+
+    Args:
+      cmd_fragment (list[str]): The dut_control command to run.
+      verbose (bool): Whether to print the command before it's run.
+      dryrun (bool): Whether to actually execute the command or just print it.
+    """
+    cros_build_lib.run(
+        self._base_cmd + cmd_fragment, print_cmd=verbose, dryrun=dryrun)
+
+  def run_all(self, cmd_fragments, verbose=False, dryrun=False):
+    """Run multiple dut_control commands in the order given.
+
+    Args:
+      cmd_fragments (list[list[str]]): The dut_control commands to run.
+      verbose (bool): Whether to print the commands as they are run.
+      dryrun (bool): Whether to actually execute the command or just print it.
+    """
+    for cmd in cmd_fragments:
+      self.run(cmd, verbose=verbose, dryrun=dryrun)
+
+  def servo_run(self, dut_cmd_on, dut_cmd_off, flash_cmd, verbose, dryrun):
+    """Runs subprocesses for setting dut controls and executing flash_cmd.
+
+    Args:
+      dut_cmd_on ([[str]]): 2d array of dut-control commands
+        in the form [['dut-control', 'cmd1', 'cmd2'...],
+        ['dut-control', 'cmd3'...]]
+        that get executed before the dut_cmd.
+      dut_cmd_off ([[str]]): 2d array of dut-control commands
+        in the same form that get executed after the dut_cmd.
+      flash_cmd ([str]): array containing all arguments for
+        the actual command. Run as root user on host.
+      verbose (bool): if True then print out the various
+        commands before running them.
+      dryrun (bool): if True then print the commands without executing.
+
+    Returns:
+      bool: True if commands were run successfully, otherwise False.
+    """
+    success = True
+    try:
+      # Dut on command runs.
+      self.run_all(dut_cmd_on, verbose=verbose, dryrun=dryrun)
+
+      # Need to wait for SPI chip power to stabilize (for some designs)
+      time.sleep(1)
+
+      # Run the flash command.
+      cros_build_lib.sudo_run(flash_cmd, print_cmd=verbose, dryrun=dryrun)
+    except cros_build_lib.CalledProcessError:
+      logging.error('DUT command failed, see output above for more info.')
+      success = False
+    finally:
+      # Run the dut off commands to clean up state if possible.
+      try:
+        self.run_all(dut_cmd_off, verbose=verbose, dryrun=dryrun)
+      except cros_build_lib.CalledProcessError:
+        logging.error('DUT cmd off failed, see output above for more info.')
+        success = False
+
+    return success
diff --git a/lib/firmware/firmware_config.py b/lib/firmware/firmware_config.py
new file mode 100644
index 0000000..b78ea19
--- /dev/null
+++ b/lib/firmware/firmware_config.py
@@ -0,0 +1,178 @@
+# Copyright 2021 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""AP Firmware Config related functionality.
+
+This module holds the firmware config objects, provides functionality to read
+the config from ap_firmware_config modules, and export it into JSON.
+"""
+
+import json
+import os
+import logging
+from pathlib import Path
+import sys
+from typing import List, NamedTuple, Optional
+
+from chromite.lib.firmware import servo_lib
+from chromite.lib.firmware import ap_firmware_config
+
+_CONFIG_BUILD_WORKON_PACKAGES = 'BUILD_WORKON_PACKAGES'
+_CONFIG_BUILD_PACKAGES = 'BUILD_PACKAGES'
+
+
+class Error(Exception):
+  """Base error class for the module."""
+
+
+class FirmwareConfig(NamedTuple):
+  """Stores firmware config for a specific board and a specific servo/ssh.
+
+  Attributes:
+    dut_control_on:  2d array formatted like [["cmd1", "arg1", "arg2"],
+                                              ["cmd2", "arg3", "arg4"]]
+                       with commands that need to be ran before flashing,
+                       where cmd1 will be run before cmd2.
+    dut_control_off: 2d array formatted like [["cmd1", "arg1", "arg2"],
+                                              ["cmd2", "arg3", "arg4"]]
+                       with commands that need to be ran after flashing,
+                       where cmd1 will be run before cmd2.
+    programmer:      programmer argument (-p) for flashrom and futility.
+    flash_extra_flags_futility: extra flags to flash with futility.
+    flash_extra_flags_flashrom: extra flags to flash with flashrom.
+
+    cros_workon_packages: packages to cros-workon before building.
+    build_packages: packages to build.
+  """
+  dut_control_on: List[List[str]]
+  dut_control_off: List[List[str]]
+  programmer: str
+  force_flashrom: bool
+  flash_extra_flags_futility: List[str]
+  flash_extra_flags_flashrom: List[str]
+  workon_packages: List[str]
+  build_packages: List[str]
+
+
+def get_config(build_target_name: str,
+               servo: Optional[servo_lib.Servo]) -> FirmwareConfig:
+  """Return config for a given build target and servo/ssh.
+
+  Args:
+    build_target_name: Name of the build target, e.g. 'dedede'.
+    servo: servo: The servo connected to the target DUT. None for SSH.
+  """
+  module = ap_firmware_config.get(build_target_name, fallback=True)
+
+  workon_packages = getattr(module, _CONFIG_BUILD_WORKON_PACKAGES, None)
+  build_packages = getattr(module, _CONFIG_BUILD_PACKAGES,
+                           ['chromeos-bootimage'])
+
+  if servo:
+    dut_control_on, dut_control_off, programmer = module.get_config(servo)
+    force_flashrom = getattr(module, 'DEPLOY_SERVO_FORCE_FLASHROM', False)
+    # Some servo variables are set to a different value by other programs.
+    # Reset them to the default and then append with variables from the
+    # config to avoid overriding config.
+    reset_dut_control_on = [['ec_uart_timeout:10']]
+    dut_control_on = reset_dut_control_on + dut_control_on
+  else:
+    dut_control_on = []
+    dut_control_off = []
+    programmer = 'host'
+    force_flashrom = getattr(module, 'DEPLOY_SSH_FORCE_FLASHROM', False)
+
+  flash_extra_flags_futility = []
+  flash_extra_flags_flashrom = []
+  if hasattr(module, 'is_fast_required') and servo:
+    if module.is_fast_required(True, servo):
+      flash_extra_flags_futility += ['--fast']
+    if module.is_fast_required(False, servo):
+      flash_extra_flags_flashrom += ['-n']
+  if hasattr(module, 'deploy_extra_flags_futility'):
+    flash_extra_flags_futility += module.deploy_extra_flags_futility(servo)
+  if hasattr(module, 'deploy_extra_flags_flashrom'):
+    flash_extra_flags_flashrom += module.deploy_extra_flags_flashrom(servo)
+
+  return FirmwareConfig(dut_control_on, dut_control_off, programmer,
+                        force_flashrom, flash_extra_flags_futility,
+                        flash_extra_flags_flashrom, workon_packages,
+                        build_packages)
+
+
+def export_config_as_json(build_targets: Optional[List[str]] = None,
+                          output_path: Optional[str] = None,
+                          serial: str = None):
+  """Exports config for all board:servo pairs in JSON.
+
+  Args:
+    build_targets: Names of the boards, e.g. ['dedede']. None for all boards.
+    output_path: Name of the output file. None for stdout.
+    serial: Serial number of the DUT. If None, %s will be used.
+  """
+  if not serial:
+    serial = '%s'
+
+  boards = []
+  if build_targets:
+    boards = build_targets
+  else:
+    # Get the board list from config python modules in ap_firmware_config
+    ap_firmware_config_path = (
+        Path(os.path.dirname(__file__)) / 'ap_firmware_config')
+    for p in ap_firmware_config_path.glob('*.py'):
+      if not p.is_file():
+        continue
+      if p.name.startswith('_'):
+        continue
+      # Remove paths, leaving only filenames, and remove .py suffixes.
+      boards.append(p.with_suffix('').name)
+  boards.sort()
+
+  if output_path:
+    logging.info('Dumping AP config to %s', output_path)
+    logging.info('List of boards: %s', ', '.join(boards))
+    logging.info('List of servos: %s', ', '.join(servo_lib.VALID_SERVOS))
+
+  output = {}
+  failed_board_servos = {}
+  for board in boards:
+    output[board] = {}
+    for servo_version in servo_lib.VALID_SERVOS + ('ssh',):
+      servo = None
+      if servo_version != 'ssh':
+        servo = servo_lib.Servo(servo_version, serial)
+      # get_config() call is expected to fail for some board:servo pairs.
+      # Disable logging to avoid inconsistent error messages from config
+      # modules' get_config() calls.
+      logging.disable(logging.CRITICAL)
+      try:
+        conf = get_config(board, servo)
+      except servo_lib.UnsupportedServoVersionError:
+        failed_board_servos.setdefault(board, []).append(servo_version)
+        continue
+      finally:
+        # Reenable logging.
+        logging.disable(logging.NOTSET)
+
+      output[board][servo_version] = {
+          'dut_control_on': conf.dut_control_on,
+          'dut_control_off': conf.dut_control_off,
+          'programmer': conf.programmer,
+          'force_flashrom': conf.force_flashrom,
+          'flash_extra_flags_futility': conf.flash_extra_flags_futility,
+          'flash_extra_flags_flashrom': conf.flash_extra_flags_flashrom,
+      }
+
+  for board, servos in failed_board_servos.items():
+    logging.info('[%s] skipping servos %s', board, ', '.join(servos))
+
+  if not output_path:
+    # Print to stdout.
+    json.dump(output, sys.stdout, ensure_ascii=False, indent=2, sort_keys=True)
+  else:
+    # Write to a file.
+    with open(output_path, 'w', encoding='utf-8') as output_file:
+      json.dump(
+          output, output_file, ensure_ascii=False, indent=2, sort_keys=True)
diff --git a/lib/firmware/firmware_lib.py b/lib/firmware/firmware_lib.py
new file mode 100644
index 0000000..ac7ede6
--- /dev/null
+++ b/lib/firmware/firmware_lib.py
@@ -0,0 +1,474 @@
+# Copyright 2021 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Utilities to do build, flash, read, and other operations with AP Firmware.
+"""
+
+import logging
+import os
+import shutil
+import tempfile
+from typing import Iterable, Optional
+
+from chromite.lib import build_target_lib
+from chromite.lib import commandline
+from chromite.lib import cros_build_lib
+from chromite.lib import osutils
+from chromite.lib import portage_util
+from chromite.lib import workon_helper
+from chromite.lib.firmware import firmware_config
+from chromite.lib.firmware import dut
+from chromite.service import sysroot
+
+
+class Error(Exception):
+  """Base module error class."""
+
+
+class DeployFailed(Error):
+  """Error raised when deploy fails."""
+
+
+class BuildError(Error):
+  """Failure in the build command."""
+
+
+class CleanError(Error):
+  """Failure in the clean command."""
+
+
+def deploy(build_target,
+           image,
+           device=None,
+           flashrom=False,
+           port=None,
+           verbose=False,
+           dryrun=False,
+           flash_contents: Optional[str] = None,
+           passthrough_args: Iterable[str] = tuple()):
+  """Deploy an AP FW image to a device.
+
+  Args:
+    build_target (build_target_lib.BuildTarget): The DUT build target.
+    image (str): The image path.
+    device (commandline.Device): The device to be used. Temporarily optional.
+    flashrom (bool): Whether to use flashrom or futility.
+    port (int|None): The servo port.
+    verbose (bool): Whether to use verbose output for flash commands.
+    dryrun (bool): Whether to actually execute the deployment or just print the
+      operations that would have been performed.
+    flash_contents: Path to the file that contains the existing contents.
+    passthrough_args: List of additional options passed to flashrom or futility.
+  """
+  ip = None
+  if device:
+    port = device.port
+    if device.scheme == commandline.DEVICE_SCHEME_SSH:
+      ip = device.hostname
+      port = port or device.port
+  else:
+    ip = os.getenv('IP')
+
+  if ip:
+    _deploy_ssh(build_target, image, flashrom, verbose, ip, port, dryrun,
+                passthrough_args)
+  else:
+    _deploy_servo(build_target, image, flashrom, verbose, port, dryrun,
+                  flash_contents, passthrough_args)
+
+
+def _deploy_servo(build_target,
+                  image,
+                  flashrom,
+                  verbose,
+                  port,
+                  dryrun,
+                  flash_contents: Optional[str] = None,
+                  passthrough_args: Iterable[str] = tuple()):
+  """Deploy to a servo connection.
+
+  Args:
+    build_target (build_target_lib.BuildTarget): The DUT build target.
+    image (str): Path to the image to flash.
+    flashrom (bool): Whether to use flashrom or futility.
+    verbose (bool): Whether to use verbose output for flash commands.
+    port (int|None): The servo port.
+    dryrun (bool): Whether to actually execute the deployment or just print the
+      operations that would have been performed.
+    flash_contents: Path to the file that contains the existing contents.
+    passthrough_args: Additional options passed to flashrom or futility.
+  """
+  dut_ctl = dut.DutControl(port)
+  servo = dut_ctl.get_servo()
+  fw_config = firmware_config.get_config(build_target.name, servo)
+
+  use_flashrom = flashrom or fw_config.force_flashrom
+  logging.notice('Attempting to flash via servo using %s.',
+                 'flashrom' if use_flashrom else 'futility')
+
+  flashrom_cmd = ['flashrom', '-p', fw_config.programmer, '-w', image]
+  futility_cmd = [
+      'futility',
+      'update',
+      '-p',
+      fw_config.programmer,
+      '-i',
+      image,
+  ]
+  futility_cmd += ['--force', '--wp=0']
+  if verbose:
+    flashrom_cmd += ['-V']
+    futility_cmd += ['-v']
+  if flash_contents is not None:
+    flashrom_cmd += ['--flash-contents', flash_contents]
+  if passthrough_args:
+    flashrom_cmd += passthrough_args
+    futility_cmd += passthrough_args
+
+  if use_flashrom and fw_config.flash_extra_flags_flashrom:
+    if passthrough_args:
+      logging.warning(
+          'Extra flashing arguments provided in CLI (%s) '
+          'override arguments provided by config file (%s)', passthrough_args,
+          fw_config.flash_extra_flags_flashrom)
+    else:
+      flashrom_cmd += fw_config.flash_extra_flags_flashrom
+
+  if not use_flashrom and fw_config.flash_extra_flags_futility:
+    if passthrough_args:
+      logging.warning(
+          'Extra flashing arguments provided in CLI (%s) '
+          'override arguments provided by config file (%s)', passthrough_args,
+          fw_config.flash_extra_flags_futility)
+    else:
+      futility_cmd += fw_config.flash_extra_flags_futility
+
+  flash_cmd = flashrom_cmd if use_flashrom else futility_cmd
+  if dut_ctl.servo_run(fw_config.dut_control_on, fw_config.dut_control_off,
+                       flash_cmd, verbose, dryrun):
+    logging.notice('SUCCESS. Exiting flash_ap.')
+  else:
+    logging.error('Unable to complete flash, verify servo connection '
+                  'is correct and servod is running in the background.')
+
+
+def _deploy_ssh(build_target,
+                image,
+                flashrom,
+                verbose,
+                ip,
+                port,
+                dryrun,
+                passthrough_args: Iterable[str] = tuple()):
+  """Deploy to a servo connection.
+
+  Args:
+    build_target (build_target_lib.BuildTarget): The DUT build target.
+    image (str): Path to the image to flash.
+    flashrom (bool): Whether to use flashrom or futility.
+    verbose (bool): Whether to use verbose output for flash commands.
+    ip (str): The DUT ip address.
+    port (int): The port to ssh to.
+    dryrun (bool): Whether to execute the deployment or just print the
+      commands that would have been executed.
+    passthrough_args: List of additional options passed to flashrom or futility.
+  """
+
+  fw_config = firmware_config.get_config(build_target.name, None)
+
+  use_flashrom = flashrom or fw_config.force_flashrom
+  logging.notice('Attempting to flash via ssh using %s.',
+                 'flashrom' if use_flashrom else 'futility')
+
+  logging.info('connecting to: %s\n', ip)
+  id_filename = '/mnt/host/source/chromite/ssh_keys/testing_rsa'
+  tmpfile = tempfile.NamedTemporaryFile()
+  shutil.copyfile(id_filename, tmpfile.name)
+
+  if use_flashrom and fw_config.flash_extra_flags_flashrom:
+    if passthrough_args:
+      logging.warning(
+          'Extra flashing arguments provided in CLI (%s) '
+          'override arguments provided by config file (%s)', passthrough_args,
+          fw_config.flash_extra_flags_flashrom)
+    else:
+      passthrough_args = fw_config.flash_extra_flags_flashrom
+
+  if not use_flashrom and fw_config.flash_extra_flags_futility:
+    if passthrough_args:
+      logging.warning(
+          'Extra flashing arguments provided in CLI (%s) '
+          'override arguments provided by config file (%s)', passthrough_args,
+          fw_config.flash_extra_flags_futility)
+    else:
+      passthrough_args = fw_config.flash_extra_flags_futility
+
+  scp_cmd, flash_cmd = _build_flash_ssh_cmds(not flashrom, ip, port, image,
+                                             tmpfile.name, verbose,
+                                             passthrough_args)
+  try:
+    cros_build_lib.run(scp_cmd, print_cmd=verbose, check=True, dryrun=dryrun)
+  except cros_build_lib.CalledProcessError as e:
+    logging.error('Could not copy image to dut.')
+    raise e
+
+  logging.info('Flashing now, may take several minutes.')
+  try:
+    cros_build_lib.run(flash_cmd, print_cmd=verbose, check=True, dryrun=dryrun)
+  except cros_build_lib.CalledProcessError as e:
+    logging.error('Flashing over SSH failed. Try using a servo instead.')
+    raise e
+
+  logging.notice('ssh flash successful. Exiting flash_ap')
+
+
+def _build_flash_ssh_cmds(futility,
+                          ip,
+                          port,
+                          path,
+                          tmp_file_name,
+                          verbose,
+                          passthrough_args: Iterable[str] = tuple()):
+  """Helper function to build commands for flashing over ssh
+
+  Args:
+    futility (bool): if True then flash with futility, otherwise flash
+      with flashrom.
+    ip (string): ip address of dut to flash.
+    port (int): The port to ssh to.
+    path (string): path to BIOS image to be flashed.
+    tmp_file_name (string): name of tempfile with copy of testing_rsa
+      keys.
+    verbose (bool): if True set -v flag in flash command.
+    passthrough_args: List of additional options passed to flashrom or futility.
+
+  Returns:
+    scp_cmd ([string]):
+    flash_cmd ([string]):
+  """
+  ssh_parameters = [
+      '-o', 'UserKnownHostsFile=/dev/null', '-o', 'StrictHostKeyChecking=no',
+      '-o', 'CheckHostIP=no'
+  ]
+  ssh_port = ['-p', str(port)] if port else []
+  scp_port = ['-P', str(port)] if port else []
+  tmp = '/tmp'
+  hostname = 'root@%s' % ip
+  scp_cmd = (['scp', '-i', tmp_file_name] + scp_port + ssh_parameters +
+             [path, '%s:%s' % (hostname, tmp)])
+  flash_cmd = ['ssh', hostname, '-i', tmp_file_name] + ssh_port + ssh_parameters
+  if futility:
+    flash_cmd += [
+        'futility', 'update', '-p', 'host', '-i',
+        os.path.join(tmp, os.path.basename(path))
+    ]
+    if verbose:
+      flash_cmd += ['-v']
+  else:
+    flash_cmd += [
+        'flashrom', '-p', 'host', '-w',
+        os.path.join(tmp, os.path.basename(path))
+    ]
+    if verbose:
+      flash_cmd += ['-V']
+  if passthrough_args:
+    flash_cmd.extend(passthrough_args)
+  flash_cmd += ['&& reboot']
+  return scp_cmd, flash_cmd
+
+
+def build(build_target, fw_name=None, dry_run=False):
+  """Build the AP Firmware.
+
+  Args:
+    build_target (BuildTarget): The build target (board) being built.
+    fw_name (str|None): Optionally set the FW_NAME envvar to allow building
+      the firmware for only a specific variant.
+    dry_run (bool): Whether to perform a dry run.
+  """
+  logging.notice('Building AP Firmware.')
+
+  if not os.path.exists(build_target.root):
+    logging.warning(
+        'Sysroot for target %s is not available. Attempting '
+        'to configure sysroot via default setup_board command.',
+        build_target.name)
+    try:
+      sysroot.SetupBoard(build_target)
+    except (portage_util.MissingOverlayError, sysroot.Error):
+      cros_build_lib.Die('setup_board with default specifications failed. '
+                         "Please configure the board's sysroot separately.")
+
+  config = firmware_config.get_config(build_target.name, None)
+
+  with workon_helper.WorkonScope(build_target, config.workon_packages):
+    extra_env = {'FW_NAME': fw_name} if fw_name else None
+    # Run the emerge command to build the packages. Don't raise an exception
+    # here if it fails so we can cros workon stop afterwords.
+    logging.info('Building the AP firmware packages.')
+    # Print command with --debug.
+    print_cmd = logging.getLogger(__name__).getEffectiveLevel() == logging.DEBUG
+    default_build_flags = [
+        '--deep', '--update', '--newuse', '--newrepo', '--jobs', '--verbose'
+    ]
+    result = cros_build_lib.run(
+        [build_target.get_command('emerge')] + default_build_flags +
+        list(config.build_packages),
+        print_cmd=print_cmd,
+        check=False,
+        debug_level=logging.DEBUG,
+        dryrun=dry_run,
+        extra_env=extra_env)
+
+  if result.returncode:
+    # Now raise the emerge failure since we're done cleaning up.
+    raise BuildError('The emerge command failed. '
+                     'See the emerge output above for details.')
+
+  logging.notice(
+      'AP firmware image for device %s was built successfully '
+      'and is available at %s/firmware.', build_target.name,
+      build_target.full_path())
+
+
+def ssh_read(path, verbose, ip, port, dryrun, region):
+  """This function reads AP firmware over ssh.
+
+  Tries to ssh to ip address once. If the ssh connection is successful the
+  image is read from the DUT using flashrom, and then is copied back via scp.
+
+  Args:
+    path (str): path to the BIOS image to be flashed or read.
+    verbose (bool): if True to set -v flag in flash command and
+      print other debug info, if False do nothing.
+    ip (str): ip address of DUT.
+    port (int): The port to ssh to.
+    dryrun (bool): Whether to actually execute the commands or just print
+      the commands that would have been run.
+    region (str): Region to read.
+
+  Returns:
+    bool: True on success, False on failure.
+  """
+  logging.info('Connecting to: %s\n', ip)
+  id_filename = '/mnt/host/source/chromite/ssh_keys/testing_rsa'
+  tmpfile = tempfile.NamedTemporaryFile()
+  shutil.copyfile(id_filename, tmpfile.name)
+
+  scp_cmd, flash_cmd = _build_read_ssh_cmds(ip, port, path, tmpfile.name,
+                                            verbose, region)
+
+  logging.info('Reading now, may take several minutes.')
+  try:
+    cros_build_lib.run(flash_cmd, print_cmd=verbose, check=True, dryrun=dryrun)
+  except cros_build_lib.CalledProcessError:
+    logging.error('Read failed.')
+    return False
+
+  try:
+    cros_build_lib.run(scp_cmd, print_cmd=verbose, check=True, dryrun=dryrun)
+  except cros_build_lib.CalledProcessError:
+    logging.error('Could not copy image from dut.')
+    return False
+
+  return True
+
+
+def _build_read_ssh_cmds(ip, port, path, tmp_file_name, verbose, region):
+  """Helper function to build commands for reading images over ssh
+
+  Args:
+    ip (string): ip address of DUT.
+    port (int): The port to ssh to.
+    path (string): path to store the read BIOS image.
+    tmp_file_name (string): name of tempfile with copy of testing_rsa
+      keys.
+    verbose (bool): if True set -v flag in flash command.
+    region (str): Region to read.
+
+  Returns:
+    scp_cmd ([string]):
+    flash_cmd ([string]):
+  """
+  ssh_parameters = [
+      '-o', 'UserKnownHostsFile=/dev/null', '-o', 'StrictHostKeyChecking=no',
+      '-o', 'CheckHostIP=no'
+  ]
+  ssh_port = ['-p', str(port)] if port else []
+  scp_port = ['-P', str(port)] if port else []
+  remote_path = os.path.join('/tmp', os.path.basename(path))
+  hostname = 'root@%s' % ip
+  scp_cmd = (['scp', '-i', tmp_file_name] + scp_port + ssh_parameters +
+             ['%s:%s' % (hostname, remote_path), path])
+  flash_cmd = (['ssh', hostname, '-i', tmp_file_name] + ssh_port +
+               ssh_parameters + ['flashrom', '-p', 'host', '-r', remote_path])
+  if region:
+    flash_cmd += ['-i', region]
+  if verbose:
+    flash_cmd += ['-V']
+  return scp_cmd, flash_cmd
+
+
+def clean(build_target: build_target_lib.BuildTarget, dry_run=False):
+  """Cleans packages and dependencies related to a specified target.
+
+  After running the command, the user's environment should be able to
+  successfully build packages for a target board.
+
+  Args:
+    build_target: Target board to be cleaned
+    dry_run: Indicates that packages and system files should not be modified
+  """
+  pkgs = []
+  try:
+    qfile_pkgs = cros_build_lib.run(
+        [build_target.get_command('qfile'), '/firmware'],
+        capture_output=True,
+        check=False,
+        dryrun=dry_run).stdout
+    pkgs = [l.split()[0] for l in qfile_pkgs.decode().splitlines()]
+  except cros_build_lib.RunCommandError as e:
+    raise CleanError('qfile for target board %s is not present; board may '
+                     'not have been set up.' % build_target.name)
+
+  config = firmware_config.get_config(build_target.name, None)
+  pkgs = set(pkgs).union(config.build_packages)
+  pkgs = sorted(
+      set(pkgs).union(['coreboot-private-files', 'chromeos-config-bsp']))
+
+  err = []
+  try:
+    cros_build_lib.run(
+        [build_target.get_command('emerge'), '--rage-clean', *pkgs],
+        capture_output=True,
+        dryrun=dry_run)
+  except cros_build_lib.RunCommandError as e:
+    err.append(e)
+
+  try:
+    if dry_run:
+      logging.notice('rm -rf -- /build/%s/firmware/*', build_target.name)
+    else:
+      osutils.RmDir(
+          '/build/%s/firmware/*' % build_target.name,
+          sudo=True,
+          ignore_missing=True)
+  except (EnvironmentError, cros_build_lib.RunCommandError) as e:
+    err.append(e)
+
+  if err:
+    logging.warning(
+        'All processes for %s have completed, but some were '
+        'completed with errors.', build_target.name)
+    for e in err:
+      logging.error(e)
+    raise CleanError("`cros ap clean -b %s' did not complete successfully." %
+                     build_target.name)
+
+  logging.notice(
+      'AP firmware image for device %s was successfully cleaned.'
+      '\nThe following packages were unmerged: %s'
+      '\nThe following build target directory was removed: '
+      '/build/%s/firmware', build_target.name, ' '.join(pkgs),
+      build_target.name)
diff --git a/lib/firmware/firmware_lib_unittest.py b/lib/firmware/firmware_lib_unittest.py
new file mode 100644
index 0000000..076c461
--- /dev/null
+++ b/lib/firmware/firmware_lib_unittest.py
@@ -0,0 +1,55 @@
+# Copyright 2021 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Tests for the firmware_lib module."""
+
+from unittest import mock
+
+from chromite.lib import build_target_lib
+from chromite.lib import cros_build_lib
+from chromite.lib import cros_test_lib
+from chromite.lib import osutils
+from chromite.lib.firmware import firmware_config
+from chromite.lib.firmware import firmware_lib
+
+
+class CleanTest(cros_test_lib.RunCommandTestCase):
+  """Tests for cleaning up firmware artifacts and dependencies."""
+
+  def setUp(self):
+    self.pkgs = [
+        'pkg1', 'pkg2', 'coreboot-private-files', 'chromeos-config-bsp'
+    ]
+
+  def test_clean(self):
+    """Sanity check for the clean command (ideal case)."""
+    fw_config = mock.MagicMock(
+        build_workon_packages=None, build_packages=('pkg3', 'pkg4'))
+
+    self.PatchObject(firmware_config, 'get_config', return_value=fw_config)
+
+    pkgs = [*self.pkgs, *fw_config.build_packages]
+
+    def run_side_effect(*args, **kwargs):
+      if args[0][0].startswith('qfile'):
+        if kwargs.get('capture_output'):
+          return mock.MagicMock(stdout='\n'.join(pkgs).encode())
+        return mock.MagicMock(stdout=''.encode())
+      elif args[0][0].startswith('emerge'):
+        return mock.MagicMock(returncode=0)
+
+    run_mock = self.PatchObject(
+        cros_build_lib, 'run', side_effect=run_side_effect)
+    self.PatchObject(osutils, 'RmDir')
+    firmware_lib.clean(build_target_lib.BuildTarget('boardname'))
+    run_mock.assert_any_call([mock.ANY, mock.ANY, *sorted(pkgs)],
+                             capture_output=mock.ANY,
+                             dryrun=False)
+
+  def test_nonexistent_board_clean(self):
+    """Verifies exception thrown when target board was not configured."""
+    se = cros_build_lib.RunCommandError('nonexistent board')
+    self.PatchObject(cros_build_lib, 'run', side_effect=se)
+    with self.assertRaisesRegex(firmware_lib.CleanError, 'qfile'):
+      firmware_lib.clean(build_target_lib.BuildTarget('schrodinger'))
diff --git a/lib/firmware/flash_ap.py b/lib/firmware/flash_ap.py
deleted file mode 100755
index 4256ba5..0000000
--- a/lib/firmware/flash_ap.py
+++ /dev/null
@@ -1,407 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2019 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Module to detect flashing infrastructure and flash ap firmware.
-
-This script automatically detects the flashing infrastructure and uses that to
-flash AP fw to the DUT. First it checks for the environment variable $IP, then
-tries flash via ssh to that address if one is present. If not it looks up what
-servo version is connected and uses that to flash the AP firmware. Right now
-this script only works with octopus, grunt, wilco, and hatch devices but will
-be extended to support more in the future.
-"""
-
-import logging
-import os
-import shutil
-import tempfile
-import time
-from typing import Iterable, Optional
-
-from chromite.lib import commandline
-from chromite.lib import cros_build_lib
-from chromite.lib.firmware import ap_firmware
-from chromite.lib.firmware import servo_lib
-
-
-class Error(Exception):
-  """Base module error class."""
-
-
-class DeployFailed(Error):
-  """Error raised when deploy fails."""
-
-
-class MissingBuildTargetCommandsError(Error):
-  """Error thrown when board-specific functionality can't be imported."""
-
-
-def _build_flash_ssh_cmds(futility, ip, port, path, tmp_file_name, fast,
-                          verbose, passthrough_args: Iterable[str] = tuple()):
-  """Helper function to build commands for flashing over ssh
-
-  Args:
-    futility (bool): if True then flash with futility, otherwise flash
-      with flashrom.
-    ip (string): ip address of dut to flash.
-    port (int): The port to ssh to.
-    path (string): path to BIOS image to be flashed.
-    tmp_file_name (string): name of tempfile with copy of testing_rsa
-      keys.
-    fast (bool): if True pass through --fast (-n for flashrom) to
-      flashing command.
-    verbose (bool): if True set -v flag in flash command.
-    passthrough_args: List of additional options passed to flashrom or futility.
-
-  Returns:
-    scp_cmd ([string]):
-    flash_cmd ([string]):
-  """
-  ssh_parameters = [
-      '-o', 'UserKnownHostsFile=/dev/null', '-o', 'StrictHostKeyChecking=no',
-      '-o', 'CheckHostIP=no'
-  ]
-  ssh_port = ['-p', str(port)] if port else []
-  scp_port = ['-P', str(port)] if port else []
-  tmp = '/tmp'
-  hostname = 'root@%s' % ip
-  scp_cmd = (['scp', '-i', tmp_file_name] + scp_port + ssh_parameters +
-             [path, '%s:%s' % (hostname, tmp)])
-  flash_cmd = ['ssh', hostname, '-i', tmp_file_name] + ssh_port + ssh_parameters
-  if futility:
-    flash_cmd += [
-        'futility', 'update', '-p', 'host', '-i',
-        os.path.join(tmp, os.path.basename(path))
-    ]
-    if fast:
-      flash_cmd += ['--fast']
-    if verbose:
-      flash_cmd += ['-v']
-  else:
-    flash_cmd += [
-        'flashrom', '-p', 'host', '-w',
-        os.path.join(tmp, os.path.basename(path))
-    ]
-    if fast:
-      flash_cmd += ['-n']
-    if verbose:
-      flash_cmd += ['-V']
-  if passthrough_args:
-    flash_cmd.extend(passthrough_args)
-  flash_cmd += ['&& reboot']
-  return scp_cmd, flash_cmd
-
-
-def _ssh_flash(futility, path, verbose, ip, port, fast, dryrun,
-               passthrough_args: Iterable[str] = tuple()):
-  """This function flashes AP firmware over ssh.
-
-  Tries to ssh to ip address once. If the ssh connection is successful the
-  file to be flashed is copied over to the DUT then flashed using either
-  futility or flashrom.
-
-  Args:
-    futility (bool): if True then flash with futility, otherwise flash
-      with flashrom.
-    path (str): path to the BIOS image to be flashed.
-    verbose (bool): if True to set -v flag in flash command and
-      print other debug info, if False do nothing.
-    ip (str): ip address of dut to flash.
-    port (int): The port to ssh to.
-    fast (bool): if True pass through --fast (-n for flashrom) to
-      flashing command.
-    dryrun (bool): Whether to actually execute the commands or just print
-      the commands that would have been run.
-    passthrough_args: List of additional options passed to flashrom or futility.
-
-  Returns:
-    bool: True on success, False on failure.
-  """
-  logging.info('connecting to: %s\n', ip)
-  id_filename = '/mnt/host/source/chromite/ssh_keys/testing_rsa'
-  tmpfile = tempfile.NamedTemporaryFile()
-  shutil.copyfile(id_filename, tmpfile.name)
-
-  scp_cmd, flash_cmd = _build_flash_ssh_cmds(futility, ip, port, path,
-                                             tmpfile.name, fast, verbose,
-                                             passthrough_args)
-  try:
-    cros_build_lib.run(scp_cmd, print_cmd=verbose, check=True, dryrun=dryrun)
-  except cros_build_lib.CalledProcessError:
-    logging.error('Could not copy image to dut.')
-    return False
-
-  logging.info('Flashing now, may take several minutes.')
-  try:
-    cros_build_lib.run(flash_cmd, print_cmd=verbose, check=True, dryrun=dryrun)
-  except cros_build_lib.CalledProcessError:
-    logging.error('Flashing failed.')
-    return False
-
-  return True
-
-
-def _build_read_ssh_cmds(ip, port, path, tmp_file_name, verbose, region):
-  """Helper function to build commands for reading images over ssh
-
-  Args:
-    ip (string): ip address of DUT.
-    port (int): The port to ssh to.
-    path (string): path to store the read BIOS image.
-    tmp_file_name (string): name of tempfile with copy of testing_rsa
-      keys.
-    verbose (bool): if True set -v flag in flash command.
-    region (str): Region to read.
-
-  Returns:
-    scp_cmd ([string]):
-    flash_cmd ([string]):
-  """
-  ssh_parameters = [
-      '-o', 'UserKnownHostsFile=/dev/null', '-o', 'StrictHostKeyChecking=no',
-      '-o', 'CheckHostIP=no'
-  ]
-  ssh_port = ['-p', str(port)] if port else []
-  scp_port = ['-P', str(port)] if port else []
-  remote_path = os.path.join('/tmp', os.path.basename(path))
-  hostname = 'root@%s' % ip
-  scp_cmd = (['scp', '-i', tmp_file_name] + scp_port + ssh_parameters +
-             ['%s:%s' % (hostname, remote_path), path])
-  flash_cmd = (['ssh', hostname, '-i', tmp_file_name] + ssh_port +
-               ssh_parameters + ['flashrom', '-p', 'host', '-r', remote_path])
-  if region:
-    flash_cmd += ['-i', region]
-  if verbose:
-    flash_cmd += ['-V']
-  return scp_cmd, flash_cmd
-
-
-def ssh_read(path, verbose, ip, port, dryrun, region):
-  """This function reads AP firmware over ssh.
-
-  Tries to ssh to ip address once. If the ssh connection is successful the
-  image is read from the DUT using flashrom, and then is copied back via scp.
-
-  Args:
-    path (str): path to the BIOS image to be flashed or read.
-    verbose (bool): if True to set -v flag in flash command and
-      print other debug info, if False do nothing.
-    ip (str): ip address of DUT.
-    port (int): The port to ssh to.
-    dryrun (bool): Whether to actually execute the commands or just print
-      the commands that would have been run.
-    region (str): Region to read.
-
-  Returns:
-    bool: True on success, False on failure.
-  """
-  logging.info('Connecting to: %s\n', ip)
-  id_filename = '/mnt/host/source/chromite/ssh_keys/testing_rsa'
-  tmpfile = tempfile.NamedTemporaryFile()
-  shutil.copyfile(id_filename, tmpfile.name)
-
-  scp_cmd, flash_cmd = _build_read_ssh_cmds(ip, port, path, tmpfile.name,
-                                            verbose, region)
-
-  logging.info('Reading now, may take several minutes.')
-  try:
-    cros_build_lib.run(flash_cmd, print_cmd=verbose, check=True, dryrun=dryrun)
-  except cros_build_lib.CalledProcessError:
-    logging.error('Read failed.')
-    return False
-
-  try:
-    cros_build_lib.run(scp_cmd, print_cmd=verbose, check=True, dryrun=dryrun)
-  except cros_build_lib.CalledProcessError:
-    logging.error('Could not copy image from dut.')
-    return False
-
-  return True
-
-
-def servo_run(dut_ctl, dut_cmd_on, dut_cmd_off, flash_cmd, verbose, dryrun):
-  """Runs subprocesses for setting dut controls and executing flash_cmd.
-
-  Args:
-    dut_ctl (DutControl): The dut_control command runner instance.
-    dut_cmd_on ([[str]]): 2d array of dut-control commands
-      in the form [['dut-control', 'cmd1', 'cmd2'...],
-      ['dut-control', 'cmd3'...]]
-      that get executed before the dut_cmd.
-    dut_cmd_off ([[str]]): 2d array of dut-control commands
-      in the same form that get executed after the dut_cmd.
-    flash_cmd ([str]): array containing all arguments for
-      the actual command. Run as root user on host.
-    verbose (bool): if True then print out the various
-      commands before running them.
-    dryrun (bool): Whether to actually execute the commands or just print them.
-
-  Returns:
-    bool: True if commands were run successfully, otherwise False.
-  """
-  success = True
-  try:
-    # Dut on command runs.
-    dut_ctl.run_all(dut_cmd_on, verbose=verbose, dryrun=dryrun)
-
-    # Need to wait for SPI chip power to stabilize (for some designs)
-    time.sleep(1)
-
-    # Run the flash command.
-    cros_build_lib.sudo_run(flash_cmd, print_cmd=verbose, dryrun=dryrun)
-  except cros_build_lib.CalledProcessError:
-    logging.error('DUT command failed, see output above for more info.')
-    success = False
-  finally:
-    # Run the dut off commands to clean up state if possible.
-    try:
-      dut_ctl.run_all(dut_cmd_off, verbose=verbose, dryrun=dryrun)
-    except cros_build_lib.CalledProcessError:
-      logging.error('DUT cmd off failed, see output above for more info.')
-      success = False
-
-  return success
-
-
-def deploy(build_target,
-           image,
-           device=None,
-           flashrom=False,
-           fast=False,
-           port=None,
-           verbose=False,
-           dryrun=False,
-           flash_contents: Optional[str] = None,
-           passthrough_args: Iterable[str] = tuple()):
-  """Deploy an AP FW image to a device.
-
-  Args:
-    build_target (build_target_lib.BuildTarget): The DUT build target.
-    image (str): The image path.
-    device (commandline.Device): The device to be used. Temporarily optional.
-    flashrom (bool): Whether to use flashrom or futility.
-    fast (bool): Whether to do a fast (no verification) flash.
-    port (int|None): The servo port.
-    verbose (bool): Whether to use verbose output for flash commands.
-    dryrun (bool): Whether to actually execute the deployment or just print the
-      operations that would have been performed.
-    flash_contents: Path to the file that contains the existing contents.
-    passthrough_args: List of additional options passed to flashrom or futility.
-  """
-  ip = None
-  if device:
-    port = device.port
-    if device.scheme == commandline.DEVICE_SCHEME_SSH:
-      ip = device.hostname
-      port = port or device.port
-  else:
-    ip = os.getenv('IP')
-
-  module = ap_firmware.get_config_module(build_target.name)
-
-  if ip:
-    _deploy_ssh(image, module, flashrom, fast, verbose, ip, port, dryrun,
-                passthrough_args)
-  else:
-    _deploy_servo(image, module, flashrom, fast, verbose, port, dryrun,
-                  flash_contents, passthrough_args)
-
-
-def _deploy_servo(image,
-                  module,
-                  flashrom,
-                  fast,
-                  verbose,
-                  port,
-                  dryrun,
-                  flash_contents: Optional[str] = None,
-                  passthrough_args: Iterable[str] = tuple()):
-  """Deploy to a servo connection.
-
-  Args:
-    image (str): Path to the image to flash.
-    module: The config module.
-    flashrom (bool): Whether to use flashrom or futility.
-    fast (bool): Whether to do a fast (no verification) flash.
-    verbose (bool): Whether to use verbose output for flash commands.
-    port (int|None): The servo port.
-    dryrun (bool): Whether to actually execute the deployment or just print the
-      operations that would have been performed.
-    flash_contents: Path to the file that contains the existing contents.
-    passthrough_args: Additional options passed to flashrom or futility.
-  """
-  logging.notice('Attempting to flash via servo.')
-  dut_ctl = servo_lib.DutControl(port)
-  servo = servo_lib.get(dut_ctl)
-  # TODO(b/143240576): Fast mode is sometimes necessary to flash successfully.
-  if (not fast and hasattr(module, 'is_fast_required') and
-      module.is_fast_required(not flashrom, servo)):
-    logging.notice('There is a known error with the board and servo type being '
-                   'used, enabling --fast to bypass this problem.')
-    fast = True
-  if (hasattr(module, 'DEPLOY_SERVO_FORCE_FLASHROM') and
-      module.DEPLOY_SERVO_FORCE_FLASHROM):
-    # Futility needs VBoot to flash so boards without functioning VBoot
-    # can set this attribute to True to force the use of flashrom.
-    flashrom = True
-  ap_config = module.get_config(servo)
-  flashrom_cmd = ['flashrom', '-p', ap_config.programmer, '-w', image]
-  futility_cmd = [
-      'futility',
-      'update',
-      '-p',
-      ap_config.programmer,
-      '-i',
-      image,
-  ]
-  futility_cmd += ['--force', '--wp=0']
-  if fast:
-    futility_cmd += ['--fast']
-    flashrom_cmd += ['-n']
-  if verbose:
-    flashrom_cmd += ['-V']
-    futility_cmd += ['-v']
-  if flash_contents is not None:
-    flashrom_cmd += ['--flash-contents', flash_contents]
-  if passthrough_args:
-    flashrom_cmd.extend(passthrough_args)
-    futility_cmd.extend(passthrough_args)
-  flash_cmd = flashrom_cmd if flashrom else futility_cmd
-  if servo_run(dut_ctl, ap_config.dut_control_on, ap_config.dut_control_off,
-               flash_cmd, verbose, dryrun):
-    logging.notice('SUCCESS. Exiting flash_ap.')
-  else:
-    logging.error('Unable to complete flash, verify servo connection '
-                  'is correct and servod is running in the background.')
-
-
-def _deploy_ssh(image, module, flashrom, fast, verbose, ip, port, dryrun,
-                passthrough_args: Iterable[str] = tuple()):
-  """Deploy to a servo connection.
-
-  Args:
-    image (str): Path to the image to flash.
-    module: The config module.
-    flashrom (bool): Whether to use flashrom or futility.
-    fast (bool): Whether to do a fast (no verification) flash.
-    verbose (bool): Whether to use verbose output for flash commands.
-    ip (str): The DUT ip address.
-    port (int): The port to ssh to.
-    dryrun (bool): Whether to execute the deployment or just print the
-      commands that would have been executed.
-    passthrough_args: List of additional options passed to flashrom or futility.
-  """
-  logging.notice('Attempting to flash via ssh.')
-  # TODO(b/143241417): Can't use flashrom over ssh on wilco.
-  if (hasattr(module, 'DEPLOY_SSH_FORCE_FUTILITY') and
-      module.DEPLOY_SSH_FORCE_FUTILITY and flashrom):
-    logging.warning('Flashing with flashrom over ssh on this device fails '
-                    'consistently, flashing with futility instead.')
-    flashrom = False
-  if _ssh_flash(not flashrom, image, verbose, ip, port, fast, dryrun,
-                passthrough_args):
-    logging.notice('ssh flash successful. Exiting flash_ap')
-  else:
-    raise DeployFailed('ssh failed, try using a servo connection instead.')
diff --git a/lib/firmware/servo_lib.py b/lib/firmware/servo_lib.py
index cc84f5c..78d64d2 100644
--- a/lib/firmware/servo_lib.py
+++ b/lib/firmware/servo_lib.py
@@ -2,51 +2,133 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-"""Servo-related functionality."""
+"""Servo-related functionality.
 
-import logging
+This module keeps a list of all valid servos, and provides utility functions
+to simplify checking whether a given servo name has a property, such as being a
+CCD/servo v4/servo micro.
+"""
 from typing import List, NamedTuple
 
-from chromite.lib import cros_build_lib
-
 SERVO_C2D2 = 'c2d2'
 SERVO_CCD_CR50 = 'ccd_cr50'
 SERVO_CCD_TI50 = 'ccd_ti50'
+SERVO_CCD_GSC = 'ccd_gsc'
 SERVO_MICRO = 'servo_micro'
 SERVO_V2 = 'servo_v2'
+SERVO_V4_C2D2 = 'servo_v4_with_c2d2'
 SERVO_V4_CCD = 'servo_v4_with_ccd'
 SERVO_V4_CCD_CR50 = 'servo_v4_with_ccd_cr50'
 SERVO_V4_CCD_TI50 = 'servo_v4_with_ccd_ti50'
+SERVO_V4_CCD_GSC = 'servo_v4_with_ccd_gsc'
 SERVO_V4_MICRO = 'servo_v4_with_servo_micro'
+SERVO_V4P1_C2D2 = 'servo_v4p1_with_c2d2'
+SERVO_V4P1_CCD = 'servo_v4p1_with_ccd'
+SERVO_V4P1_CCD_CR50 = 'servo_v4p1_with_ccd_cr50'
+SERVO_V4P1_CCD_TI50 = 'servo_v4p1_with_ccd_ti50'
+SERVO_V4P1_CCD_GSC = 'servo_v4p1_with_ccd_gsc'
+SERVO_V4P1_MICRO = 'servo_v4p1_with_servo_micro'
 
 VALID_SERVOS = (
     SERVO_C2D2,
     SERVO_CCD_CR50,
     SERVO_CCD_TI50,
+    SERVO_CCD_GSC,
     SERVO_MICRO,
     SERVO_V2,
+    SERVO_V4_C2D2,
     SERVO_V4_CCD,
     SERVO_V4_CCD_CR50,
     SERVO_V4_CCD_TI50,
+    SERVO_V4_CCD_GSC,
     SERVO_V4_MICRO,
+    SERVO_V4P1_C2D2,
+    SERVO_V4P1_CCD,
+    SERVO_V4P1_CCD_CR50,
+    SERVO_V4P1_CCD_TI50,
+    SERVO_V4P1_CCD_GSC,
+    SERVO_V4P1_MICRO,
 )
 
-CCD_SERVOS = (SERVO_CCD_CR50, SERVO_CCD_TI50, SERVO_V4_CCD, SERVO_V4_CCD_CR50,
-              SERVO_V4_CCD_TI50)
-MICRO_SERVOS = (SERVO_MICRO, SERVO_V4_MICRO)
+CCD_SERVOS = (
+    SERVO_CCD_CR50,
+    SERVO_CCD_TI50,
+    SERVO_CCD_GSC,
+    SERVO_V4_CCD,
+    SERVO_V4_CCD_CR50,
+    SERVO_V4_CCD_TI50,
+    SERVO_V4_CCD_GSC,
+    SERVO_V4P1_CCD,
+    SERVO_V4P1_CCD_CR50,
+    SERVO_V4P1_CCD_TI50,
+    SERVO_V4P1_CCD_GSC,
+)
+MICRO_SERVOS = (SERVO_MICRO, SERVO_V4_MICRO, SERVO_V4P1_MICRO)
 V2_SERVOS = (SERVO_V2,)
-V4_SERVOS = (SERVO_V4_CCD, SERVO_V4_CCD_CR50, SERVO_V4_MICRO, SERVO_V4_CCD_TI50)
+V4_SERVOS = (SERVO_V4_C2D2, SERVO_V4_CCD, SERVO_V4_CCD_CR50, SERVO_V4_MICRO,
+             SERVO_V4_CCD_TI50, SERVO_V4P1_C2D2, SERVO_V4P1_CCD,
+             SERVO_V4P1_CCD_CR50, SERVO_V4P1_CCD_TI50, SERVO_V4P1_MICRO,
+             SERVO_V4_CCD_GSC, SERVO_V4P1_CCD_GSC)
+C2D2_SERVOS = (SERVO_C2D2, SERVO_V4_C2D2, SERVO_V4P1_C2D2)
 
 _SERIAL_NUMBER_OPTION = 'serialname'
 _SERIAL_NUMBER_OPTION_OVERRIDE = {
     SERVO_V4_CCD: 'ccd_serialname',
     SERVO_V4_CCD_CR50: 'ccd_serialname',
     SERVO_V4_CCD_TI50: 'ccd_serialname',
+    SERVO_V4_CCD_GSC: 'ccd_serialname',
     SERVO_V4_MICRO: 'servo_micro_serialname',
+    SERVO_V4P1_CCD: 'ccd_serialname',
+    SERVO_V4P1_CCD_CR50: 'ccd_serialname',
+    SERVO_V4P1_CCD_TI50: 'ccd_serialname',
+    SERVO_V4P1_CCD_GSC: 'ccd_serialname',
+    SERVO_V4P1_MICRO: 'servo_micro_serialname',
 }
 
 
-class FirmwareConfig(NamedTuple):
+def get_serial_option(servo_type: str) -> str:
+  """Returns the variable to be used with a given servo to get DUT's serial."""
+  return _SERIAL_NUMBER_OPTION_OVERRIDE.get(servo_type, _SERIAL_NUMBER_OPTION)
+
+
+class Error(Exception):
+  """Base error class for the module."""
+
+
+class UnsupportedServoVersionError(Error):
+  """Unsupported servo version error (e.g. some servos do not support CCD)."""
+
+
+class Servo(object):
+  """Data class for servos."""
+
+  def __init__(self, servo_type, serial):
+    assert servo_type in VALID_SERVOS
+    self.version = servo_type
+    self.serial = serial
+
+  @property
+  def is_ccd(self):
+    return self.version in CCD_SERVOS
+
+  @property
+  def is_c2d2(self):
+    return self.version in C2D2_SERVOS
+
+  @property
+  def is_micro(self):
+    return self.version in MICRO_SERVOS
+
+  @property
+  def is_v2(self):
+    return self.version in V2_SERVOS
+
+  @property
+  def is_v4(self):
+    return self.version in V4_SERVOS
+
+
+class ServoConfig(NamedTuple):
   """Stores dut controls for specific servos.
 
   Attributes:
@@ -63,108 +145,3 @@
   dut_control_on: List[List[str]]
   dut_control_off: List[List[str]]
   programmer: str
-
-
-class Error(Exception):
-  """Base error class for the module."""
-
-
-class InvalidServoVersionError(Error):
-  """Invalid servo version error."""
-
-
-class UnsupportedServoVersionError(Error):
-  """Unsupported servo version error (e.g. some servos do not support CCD)."""
-
-
-class DutConnectionError(Error):
-  """Error when fetching data from a dut."""
-
-
-class DutControl(object):
-  """Wrapper for dut_control calls."""
-
-  def __init__(self, port):
-    self._base_cmd = ['dut-control']
-    if port:
-      self._base_cmd.append('--port=%s' % port)
-
-  def get_value(self, arg):
-    """Get the value of |arg| from dut_control."""
-    try:
-      result = cros_build_lib.run(
-          self._base_cmd + [arg], stdout=True, encoding='utf-8')
-    except cros_build_lib.CalledProcessError as e:
-      logging.debug('dut-control error: %s', str(e))
-      raise DutConnectionError(
-          'Could not establish servo connection. Verify servod is running in '
-          'the background, and the servo is properly connected.')
-
-    # Return value from the "key:value" output.
-    return result.stdout.partition(':')[2].strip()
-
-  def run(self, cmd_fragment, verbose=False, dryrun=False):
-    """Run a dut_control command.
-
-    Args:
-      cmd_fragment (list[str]): The dut_control command to run.
-      verbose (bool): Whether to print the command before it's run.
-      dryrun (bool): Whether to actually execute the command or just print it.
-    """
-    cros_build_lib.run(
-        self._base_cmd + cmd_fragment, print_cmd=verbose, dryrun=dryrun)
-
-  def run_all(self, cmd_fragments, verbose=False, dryrun=False):
-    """Run multiple dut_control commands in the order given.
-
-    Args:
-      cmd_fragments (list[list[str]]): The dut_control commands to run.
-      verbose (bool): Whether to print the commands as they are run.
-      dryrun (bool): Whether to actually execute the command or just print it.
-    """
-    for cmd in cmd_fragments:
-      self.run(cmd, verbose=verbose, dryrun=dryrun)
-
-
-class Servo(object):
-  """Data class for servos."""
-
-  def __init__(self, version, serial):
-    assert version in VALID_SERVOS
-    self.version = version
-    self.serial = serial
-
-  @property
-  def is_ccd(self):
-    return self.version in CCD_SERVOS
-
-  @property
-  def is_c2d2(self):
-    return self.version == SERVO_C2D2
-
-  @property
-  def is_micro(self):
-    return self.version in MICRO_SERVOS
-
-  @property
-  def is_v2(self):
-    return self.version in V2_SERVOS
-
-  @property
-  def is_v4(self):
-    return self.version in V4_SERVOS
-
-
-def get(dut_ctl: DutControl) -> Servo:
-  """Get the Servo instance the given dut_control command is using.
-
-  Args:
-    dut_ctl: The dut_control command wrapper instance.
-  """
-  version = dut_ctl.get_value('servo_type')
-  if version not in VALID_SERVOS:
-    raise InvalidServoVersionError('Unrecognized servo version: %s' % version)
-
-  option = _SERIAL_NUMBER_OPTION_OVERRIDE.get(version, _SERIAL_NUMBER_OPTION)
-  serial = dut_ctl.get_value(option)
-  return Servo(version, serial)
diff --git a/lib/gclient.py b/lib/gclient.py
index 682c973..63c8478 100644
--- a/lib/gclient.py
+++ b/lib/gclient.py
@@ -116,7 +116,7 @@
     Tuple of (name, url, deps_file).
   """
   if rev is None or git.IsSHA1(rev) or rev == 'HEAD':
-    # Regular chromium checkout; src may float to origin/master or be pinned.
+    # Regular chromium checkout; src may float to origin/main or be pinned.
     url = constants.CHROMIUM_GOB_URL
 
     if rev:
@@ -206,7 +206,7 @@
   """Initialize the specified directory as a gclient checkout.
 
   For gclient documentation, see:
-    http://src.chromium.org/svn/trunk/tools/depot_tools/README.gclient
+    https://chromium.googlesource.com/chromium/tools/depot_tools/+/HEAD/README.gclient.md
 
   Args:
     gclient: Path to gclient.
diff --git a/lib/gerrit.py b/lib/gerrit.py
index 1c10d15..879488f 100644
--- a/lib/gerrit.py
+++ b/lib/gerrit.py
@@ -7,6 +7,7 @@
 import logging
 import operator
 import re
+from typing import Tuple
 
 from chromite.lib import config_lib
 from chromite.lib import constants
@@ -98,6 +99,33 @@
       else:
         gob_util.MarkNotPrivate(self.host, change)
 
+  def SetAttentionSet(self, change: str, add: Tuple[str, ...] = (),
+                      remove: Tuple[str, ...] = (), dryrun: bool = False,
+                      notify: str = 'ALL', message: str = 'gerrit CLI'):
+    """Modify the attention set of a gerrit change.
+
+    Args:
+      change: ChangeId or change number for a gerrit review.
+      add: Sequence of email addresses to add to attention set.
+      remove: Sequence of email addresses to remove from attention set.
+      dryrun: If True, only print what would have been done.
+      notify: A string, parameter controlling gerrit's email generation.
+      message: A string, setting the reason for changing the attention set.
+    """
+    if add:
+      if dryrun:
+        logging.info('Would have added %s to "%s" attention set', add, change)
+      else:
+        gob_util.AddAttentionSet(self.host, change, add, notify=notify,
+                                 reason=message)
+    if remove:
+      if dryrun:
+        logging.info('Would have removed %s from "%s" attention set', remove,
+                     change)
+      else:
+        gob_util.RemoveAttentionSet(self.host, change, remove, notify=notify,
+                                    reason=message)
+
   def SetReviewers(self, change, add=(), remove=(), dryrun=False, notify='ALL'):
     """Modify the list of reviewers on a gerrit change.
 
@@ -285,6 +313,7 @@
       change = None
     elif change and cros_patch.ParseFullChangeID(change):
       change = cros_patch.ParseFullChangeID(change)
+      assert change  # Help the type checker.
       kwargs['change'] = change.change_id
       kwargs['project'] = change.project
       kwargs['branch'] = change.branch
@@ -381,6 +410,38 @@
 
     return change
 
+  def CreateChange(self, project: str, branch: str, message: str,
+                   publish: bool) -> cros_patch.GerritPatch:
+    """Creates an empty change.
+
+    The change will be empty of any file modifications. Use ChangeEdit below
+    to add file modifications to the change.
+
+    Args:
+      project: The name of the gerrit project for the change.
+      branch: Branch for the change.
+      message: Initial commit message for the change.
+      publish: If True, will publish the CL after uploading. Stays in WIP mode
+          otherwise.
+
+    Returns:
+      A cros_patch.GerritChange for the created change.
+    """
+    resp = gob_util.CreateChange(self.host, project, branch, message, publish)
+    patch_dict = cros_patch.GerritPatch.ConvertQueryResults(resp, self.host)
+    return cros_patch.GerritPatch(patch_dict, self.remote, '')
+
+  def ChangeEdit(self, change: str, path: str, contents: str) -> None:
+    """Attaches file modifications to an open change.
+
+    Args:
+      change: A gerrit change number.
+      path: Path of the file in the repo to modify.
+      contents: New contents of the file.
+    """
+    gob_util.ChangeEdit(self.host, change, path, contents)
+    gob_util.PublishChangeEdit(self.host, change)
+
   def SetReview(self, change, msg=None, labels=None, notify='ALL',
                 reviewers=None, cc=None, ready=None, wip=None, dryrun=False):
     """Update the review labels on a gerrit change.
@@ -541,8 +602,10 @@
 
   def _get_changenumber_from_stdout(self, stdout):
     """Retrieve the change number written in the URL of the git stdout."""
-    match = re.search(r'^remote:\s+[^\s]+/\+/(?P<changenum>[0-9]+)',
-                      stdout,flags=re.MULTILINE)
+    url = git.GetUrlFromRemoteOutput(stdout)
+    if not url:
+      return None
+    match = re.search(r'(?P<changenum>[0-9]+)$', url)
     if match:
       return match['changenum']
     return None
@@ -551,6 +614,9 @@
                         **kwargs):
     """Upload a change and retrieve a GerritPatch describing it.
 
+    This requires a copy of the project checked out locally. To create a
+    GerritPatch without a local checkout, use CreateChange() below.
+
     Args:
       cwd: The repository that we are working on.
       remote: The remote to upload changes to.
@@ -570,7 +636,7 @@
 
     # Upload the local changes to remote.
     ret = git.RunGit(cwd, ['push', remote,
-                     f'HEAD:refs/for/{ref}%notify={notify}'])
+                           f'HEAD:refs/for/{ref}%notify={notify}'])
     change_number = self._get_changenumber_from_stdout(ret.stdout)
 
     # If we fail to grab a change number from the stdout then fall back to the
diff --git a/lib/gerrit_unittest.py b/lib/gerrit_unittest.py
index 14c130c..235d0a7 100644
--- a/lib/gerrit_unittest.py
+++ b/lib/gerrit_unittest.py
@@ -2,10 +2,15 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-"""Unittests for GerritHelper."""
+"""Unittests for GerritHelper.
+
+Most of the tests in this file reach out to a staging/test Gerrit server. By
+default, this server is t3st-chr0m3-review.googlesource.com. These tests will
+be skipped unless run_tests is passed the '--network' arg:
+$ ./run_tests --network -- lib/gerrit_unittest.py
+"""
 
 import collections
-import getpass
 import http.client
 import http.cookiejar
 import io
@@ -103,6 +108,10 @@
         ['git', 'config', '--global', 'http.cookiefile', gi.cookies_path],
         quiet=True)
 
+    # If you're seeing "does not look like a Netscape format cookies file"
+    # errors here, make sure the first line in your gitcookies file is:
+    # "# HTTP Cookie File"
+    # TODO(b/210490942): Detect and handle this automatically.
     jar = http.cookiejar.MozillaCookieJar(gi.cookies_path)
     jar.load(ignore_expires=True)
 
@@ -161,13 +170,13 @@
     body = {
         'description': description,
         'submit_type': submit_type,
+        'branches': ['main'],
     }
     if owners is not None:
       body['owners'] = owners
     path = 'projects/%s' % urllib.parse.quote(name, '')
-    conn = gob_util.CreateHttpConn(
+    response = gob_util.CreateHttpConn(
         self.gerrit_instance.gerrit_host, path, reqtype='PUT', body=body)
-    response = conn.getresponse()
     self.assertEqual(201, response.status,
                      'Expected 201, got %s' % response.status)
     s = io.BytesIO(response.read())
@@ -277,23 +286,23 @@
     return (sha1, change_id)
 
   @staticmethod
-  def _UploadChange(clone_path, branch='master', remote='origin'):
+  def _UploadChange(clone_path, branch='main', remote='origin'):
     cros_build_lib.run(
         ['git', 'push', remote, 'HEAD:refs/for/%s' % branch], cwd=clone_path,
         quiet=True)
 
-  def uploadChange(self, clone_path, branch='master', remote='origin'):
+  def uploadChange(self, clone_path, branch='main', remote='origin'):
     """Create a gerrit CL from the HEAD of a git checkout."""
     clone_path = os.path.join(self.tempdir, clone_path)
     self._UploadChange(clone_path, branch, remote)
 
   @staticmethod
-  def _PushBranch(clone_path, branch='master'):
+  def _PushBranch(clone_path, branch='main'):
     cros_build_lib.run(
         ['git', 'push', 'origin', 'HEAD:refs/heads/%s' % branch],
         cwd=clone_path, quiet=True)
 
-  def pushBranch(self, clone_path, branch='master'):
+  def pushBranch(self, clone_path, branch='main'):
     """Push a branch directly to gerrit, bypassing code review."""
     clone_path = os.path.join(self.tempdir, clone_path)
     self._PushBranch(clone_path, branch)
@@ -314,9 +323,8 @@
       if isinstance(groups, str):
         groups = [groups]
       body['groups'] = groups
-    conn = gob_util.CreateHttpConn(
+    response = gob_util.CreateHttpConn(
         self.gerrit_instance.gerrit_host, path, reqtype='PUT', body=body)
-    response = conn.getresponse()
     self.assertEqual(201, response.status)
     s = io.BytesIO(response.read())
     self.assertEqual(b")]}'", s.readline().rstrip())
@@ -344,7 +352,9 @@
       A GerritPatch object.
     """
     (revision, changeid) = self.createCommit(clone_path, **kwargs)
-    gpatch = self.CreateGerritPatch(clone_path, remote, project=project)
+    helper = self._GetHelper()
+    gpatch = helper.CreateGerritPatch(clone_path, remote, 'main',
+                                      project=project)
     self.assertEqual(gpatch.change_id, changeid)
     self.assertEqual(gpatch.revision, revision)
     return gpatch
@@ -412,25 +422,66 @@
     project = self.createProject('testProject')
     clone_path = self.cloneProject(project)
     for _ in range(5):
-      (master_sha1, _) = self.createCommit(clone_path)
-    self.pushBranch(clone_path, 'master')
+      (main_sha1, _) = self.createCommit(clone_path)
+    self.pushBranch(clone_path, 'main')
     for _ in range(5):
       (testbranch_sha1, _) = self.createCommit(clone_path)
     self.pushBranch(clone_path, 'testbranch')
     helper = self._GetHelper()
     self.assertEqual(
-        helper.GetLatestSHA1ForBranch(project, 'master'),
-        master_sha1)
+        helper.GetLatestSHA1ForBranch(project, 'main'),
+        main_sha1)
     self.assertEqual(
         helper.GetLatestSHA1ForBranch(project, 'testbranch'),
         testbranch_sha1)
 
+  def testChangeEdit(self):
+    """Verifies that CreateChange & ChangeEdit can create CLs with changes."""
+    project = self.createProject('testProject')
+    # Gerrit returns "Destination branch does not exist" errors if we don't push
+    # something onto the new project's branch.
+    clone_path = self.cloneProject(project)
+    self.createCommit(clone_path)
+    self.pushBranch(clone_path, 'main')
+    helper = self._GetHelper()
+    # There should be no changes in our project that touch some_file.
+    file_path = 'some_file'
+    self.assertEqual(len(helper.Query(project=project, path=file_path)), 0)
+    change = helper.CreateChange(project, 'main', 'Test Change', True)
+    helper.ChangeEdit(change.gerrit_number, file_path, 'some file contents')
+    # After creating the change and adding a file modification, there should be
+    # a single change that touches some_file in our project.
+    self.assertEqual(len(helper.Query(project=project, path=file_path)), 1)
+
   def _ChooseReviewers(self):
-    all_reviewers = set(['dborowitz@google.com', 'sop@google.com',
-                         'jrn@google.com'])
-    ret = list(all_reviewers.difference(['%s@google.com' % getpass.getuser()]))
-    self.assertGreaterEqual(len(ret), 2)
-    return ret
+    # TODO(b/210507794): register some test accounts on test server. This fixed
+    # list of real IDs has a few problems, not limited to the following:
+    #  * Some functions behave differently if the account is inactive;
+    #  * Gerrit doesn't let you add yourself as a reviewer. So these accounts
+    #    can't run the tests correctly. ;)
+    return ['dborowitz@google.com', 'jrn@google.com']
+
+  def testSetAttentionSet(self):
+    """Verify that we can set the attention set on a CL."""
+    project = self.createProject('testProject')
+    clone_path = self.cloneProject(project)
+    gpatch = self.createPatch(clone_path, project)
+    emails = self._ChooseReviewers()
+    helper = self._GetHelper()
+    helper.SetReviewers(gpatch.gerrit_number, add=(
+        emails[0], emails[1]))
+    helper.SetAttentionSet(gpatch.gerrit_number, add=(
+        emails[0], emails[1]))
+    attention = gob_util.GetAttentionSet(helper.host, gpatch.gerrit_number)
+    self.assertEqual(len(attention), 2)
+    self.assertCountEqual(
+        [r['account']['email'] for r in attention],
+        [emails[0], emails[1]])
+    helper.SetAttentionSet(gpatch.gerrit_number,
+                           remove=(emails[0],))
+    attention = gob_util.GetAttentionSet(helper.host, gpatch.gerrit_number)
+    self.assertEqual(len(attention), 1)
+    self.assertEqual(attention[0]['account']['email'], emails[1])
 
   def testSetReviewers(self):
     """Verify that we can set reviewers on a CL."""
@@ -472,7 +523,7 @@
     clone_path = self.cloneProject(project)
     (sha1, _) = self.createCommit(clone_path)
     (_, changeid) = self.createCommit(clone_path)
-    self.uploadChange(clone_path, 'master')
+    self.uploadChange(clone_path, 'main')
     cros_build_lib.run(
         ['git', 'checkout', sha1], cwd=clone_path, quiet=True)
     self.createCommit(clone_path)
@@ -520,7 +571,7 @@
 
     # Query to external server by gerrit number and change-id which refer to
     # the same change should return one result.
-    fq_changeid = '~'.join((gpatch.project, 'master', gpatch.change_id))
+    fq_changeid = '~'.join((gpatch.project, 'main', gpatch.change_id))
     patch_info = gerrit.GetGerritPatchInfo([gpatch.gerrit_number, fq_changeid])
     self.assertEqual(len(patch_info), 1)
     self.assertEqual(patch_info[0].gerrit_number, gpatch.gerrit_number)
@@ -585,7 +636,7 @@
         ['git', 'commit', '--amend', '-m', new_msg], cwd=clone_path, quiet=True)
     self.uploadChange(clone_path)
     gpatch2 = self._GetHelper().QuerySingleRecord(
-        change=gpatch.change_id, project=gpatch.project, branch='master')
+        change=gpatch.change_id, project=gpatch.project, branch='main')
     self.assertNotEqual(gpatch2.approval_timestamp, 0)
     self.assertNotEqual(gpatch2.commit_timestamp, 0)
     self.assertEqual(gpatch2.approval_timestamp, gpatch2.commit_timestamp)
@@ -602,22 +653,23 @@
   def testGetChangeFromStdoutPass(self):
     """Test that the proper change number is returned from the git stdout."""
     stdout = ('remote:\nremote:\nremote:   '
-    'https://example.com/c/some/project/repo/+/123 gerrit: test')
+              'https://example.com/c/some/project/repo/+/123 gerrit: test')
     changenum = self._GetHelper()._get_changenumber_from_stdout(stdout)
     self.assertEqual(changenum, '123')
 
     stdout = ('remote:\nremote:   '
-    'https://example.com/c/some/project3/repo/+/123 gerrit: test')
+              'https://example.com/c/some/project3/repo/+/123 gerrit: test')
     changenum = self._GetHelper()._get_changenumber_from_stdout(stdout)
     self.assertEqual(changenum, '123')
 
     stdout = ('remote:   '
-    'https://example.com/c/some/project/repo/+/123 gerrit: test 456')
+              'https://example.com/c/some/project/repo/+/123 gerrit: test 456')
     changenum = self._GetHelper()._get_changenumber_from_stdout(stdout)
     self.assertEqual(changenum, '123')
 
     stdout = ('remote:   '
-    'https://example.com/c/some/project/repo/+/123 handle /+/124 in URI')
+              'https://example.com/c/some/project/repo/+/123 '
+              'handle /+/124 in URI')
     changenum = self._GetHelper()._get_changenumber_from_stdout(stdout)
     self.assertEqual(changenum, '123')
 
diff --git a/lib/git.py b/lib/git.py
index e2db06c..1fe3eb6 100644
--- a/lib/git.py
+++ b/lib/git.py
@@ -552,30 +552,6 @@
       manifest_path = os.path.join(root, '.repo', 'manifest.xml')
     return root, manifest_path
 
-  @staticmethod
-  def IsFullManifest(checkout_root):
-    """Returns True iff the given checkout is using a full manifest.
-
-    This method should go away as part of the cleanup related to brbug.com/854.
-
-    Args:
-      checkout_root: path to the root of an SDK checkout.
-
-    Returns:
-      True iff the manifest selected for the given SDK is a full manifest.
-      In this context we'll accept any manifest for which there are no groups
-      defined.
-    """
-    manifests_git_repo = os.path.join(checkout_root, '.repo', 'manifests.git')
-    cmd = ['config', '--local', '--get', 'manifest.groups']
-    result = RunGit(manifests_git_repo, cmd, check=False)
-
-    if result.output.strip():
-      # Full layouts don't define groups.
-      return False
-
-    return True
-
   def FindCheckouts(self, project, branch=None):
     """Returns the list of checkouts for a given |project|/|branch|.
 
@@ -822,7 +798,7 @@
   RunGit(git_repo, ['fetch', '--depth=1'],
          print_cmd=True, stderr=True, capture_output=False)
   # Pull the files in sparse_checkout.
-  RunGit(git_repo, ['pull', 'origin', 'master'],
+  RunGit(git_repo, ['pull', 'origin', 'HEAD'],
          print_cmd=True, stderr=True, capture_output=False)
   logging.info('ShallowFetch completed in %s.', utcnow() - start)
 
@@ -1517,7 +1493,7 @@
   corruption. Only use this if you are sure that no other git process is
   accessing the repo (such as at the beginning of a fresh build).
 
-  Args"
+  Args:
     git_repo: Directory of git repository.
   """
   git_gitdir = GetGitGitdir(git_repo)
@@ -1529,3 +1505,21 @@
       p = os.path.join(root, filename)
       logging.info('Found stale git lock, removing: %s', p)
       os.remove(p)
+
+
+def GetUrlFromRemoteOutput(remote_output: str) -> str:
+  """Retrieve the change URL from the git remote output.
+
+  The URL must begin with https://.
+
+  Args:
+    remote_output: The git remote output.
+
+  Returns:
+    URL in remote git output, or None if a URL couldn't be found.
+  """
+  match = re.search(
+      r'^remote:\s+(?P<url>https://[^\s]+)', remote_output, flags=re.MULTILINE)
+  if match:
+    return match['url']
+  return None
diff --git a/lib/git_unittest.py b/lib/git_unittest.py
index f961edc..6620e08 100644
--- a/lib/git_unittest.py
+++ b/lib/git_unittest.py
@@ -97,7 +97,7 @@
     self.assertCommandContains(['config', 'core.sparsecheckout', 'true'])
     self.assertCommandContains(['remote', 'add', 'origin', url])
     self.assertCommandContains(['fetch', '--depth=1'])
-    self.assertCommandContains(['pull', 'origin', 'master'])
+    self.assertCommandContains(['pull', 'origin', 'HEAD'])
     self.assertEqual(osutils.ReadFile(sparse_checkout),
                      'dir1/file1\ndir2/file2')
 
@@ -250,6 +250,29 @@
     self.assertExists(other_file)
     self.assertNotExists(fake_lock)
 
+  def testGetUrlFromRemoteOutput(self):
+    """Test that the proper URL is returned from the git remote output."""
+    remote_output = (
+        'remote:\nremote:\nremote:   '
+        'https://example.com/c/some/project/repo/+/123 gerrit: test')
+    url = git.GetUrlFromRemoteOutput(remote_output)
+    self.assertEqual(url, 'https://example.com/c/some/project/repo/+/123')
+
+    remote_output = (
+        'remote:\nremote:\nremote:   '
+        'https://chrome-internal-review.googlesource.com/c/chromeos/'
+        'manifest-internal/+/4298120 LTS: update kernel commit_ids for LTS '
+        'branches [NEW]  ')
+    url = git.GetUrlFromRemoteOutput(remote_output)
+    self.assertEqual(
+        url, 'https://chrome-internal-review.googlesource.com/c/chromeos/'
+        'manifest-internal/+/4298120')
+
+    remote_output = ('remote:\nremote:\nremote:   '
+                     'c/some/project/repo/+/123 gerrit: test')
+    url = git.GetUrlFromRemoteOutput(remote_output)
+    self.assertIsNone(url)
+
 
 class LogTest(cros_test_lib.RunCommandTestCase):
   """Tests for git.Log"""
diff --git a/lib/gob_util.py b/lib/gob_util.py
index 41d5377..a4939aa 100644
--- a/lib/gob_util.py
+++ b/lib/gob_util.py
@@ -7,6 +7,7 @@
 https://gerrit-review.googlesource.com/Documentation/rest-api.html
 """
 
+import base64
 import datetime
 import html.parser
 import http.client
@@ -17,7 +18,9 @@
 import re
 import socket
 import sys
+from typing import Any, Dict, Optional, Tuple, Union
 import urllib.parse
+import urllib.request
 import warnings
 
 from chromite.third_party import httplib2
@@ -174,7 +177,12 @@
   return cookies
 
 
-def CreateHttpConn(host, path, reqtype='GET', headers=None, body=None):
+def CreateHttpConn(
+    host: str,
+    path: str,
+    reqtype: Optional[str] = 'GET',
+    headers: Optional[Dict[str, str]] = None,
+    body: Optional[Union[bytes, str]] = None) -> http.client.HTTPResponse:
   """Opens an https connection to a gerrit service, and sends a request."""
   path = '/a/' + path.lstrip('/')
   headers = headers or {}
@@ -219,7 +227,7 @@
     ))
 
   if body:
-    body = json.JSONEncoder().encode(body)
+    body = json.JSONEncoder().encode(body).encode('utf-8')
     headers.setdefault('Content-Type', 'application/json')
   if logging.getLogger().isEnabledFor(logging.DEBUG):
     logging.debug('%s https://%s%s', reqtype, host, path)
@@ -229,16 +237,9 @@
       logging.debug('%s: %s', key, val)
     if body:
       logging.debug(body)
-  conn = http.client.HTTPSConnection(host)
-  conn.req_host = host
-  conn.req_params = {
-      'url': path,
-      'method': reqtype,
-      'headers': headers,
-      'body': body,
-  }
-  conn.request(**conn.req_params)
-  return conn
+  request = urllib.request.Request(
+      f'https://{host}{path}', data=body, headers=headers, method=reqtype)
+  return urllib.request.urlopen(request)
 
 
 def _InAppengine():
@@ -269,11 +270,14 @@
   """
   @timeout_util.TimeoutDecorator(REQUEST_TIMEOUT_SECONDS)
   def _FetchUrlHelper():
-    err_prefix = 'A transient error occured while querying %s:\n' % (host,)
+    err_prefix = f'A transient error occured while querying {host}/{path}\n'
     try:
-      conn = CreateHttpConn(host, path, reqtype=reqtype, headers=headers,
-                            body=body)
-      response = conn.getresponse()
+      response = CreateHttpConn(host, path, reqtype=reqtype, headers=headers,
+                                body=body)
+    except urllib.error.HTTPError as e:
+      # Any non-HTTP/2xx status is thrown as an exception even though it's the
+      # response.  We handle the actual HTTP codes below.
+      response = e
     except socket.error as ex:
       logging.warning('%s%s', err_prefix, str(ex))
       raise
@@ -285,14 +289,14 @@
       raise GOBError(http_status=response.status, reason=response.reason)
     if response.status == 404 and ignore_404:
       return b''
-    elif response.status == 200:
+    elif response.status in (200, 201):
       return response_body
 
     # Bad responses.
     logging.debug('response msg:\n%s', response.msg)
     http_version = 'HTTP/%s' % ('1.1' if response.version == 11 else '1.0')
     msg = ('%s %s %s\n%s %d %s\nResponse body: %r' %
-           (reqtype, conn.req_params['url'], http_version,
+           (reqtype, f'https://{host}/{path}', http_version,
             http_version, response.status, response.reason,
             response_body))
 
@@ -337,11 +341,6 @@
       # The 'X-ErrorId' header is set only on >= 400 response code.
       logging_function('X-ErrorId: %s', response.getheader('X-ErrorId'))
 
-    try:
-      logging.warning('conn.sock.getpeername(): %s', conn.sock.getpeername())
-    except AttributeError:
-      logging.warning('peer name unavailable')
-
     if response.status == http.client.CONFLICT:
       # 409 conflict
       if GOB_CONFLICT_ERRORS_RE.search(response_body):
@@ -501,6 +500,76 @@
   GetReviewers(host, change)
 
 
+def CreateChange(host: str, project: str, branch: str, subject: str,
+                 publish: bool) -> Dict[str, Any]:
+  """Creates an empty change.
+
+  Args:
+    host: The Gerrit host to interact with.
+    project: The name of the Gerrit project for the change.
+    branch: Branch for the change.
+    subject: Initial commit message for the change.
+    publish: If True, will publish the CL after uploading. Stays in WIP mode
+        otherwise.
+
+  Returns:
+    A JSON response dict.
+  """
+  path = 'changes/'
+  body = {'project': project, 'branch': branch, 'subject': subject}
+  if not publish:
+    body['work_in_progress'] = 'true'
+    body['notify'] = 'NONE'
+  return FetchUrlJson(host, path, body=body, reqtype='POST', ignore_404=False)
+
+
+def ChangeEdit(host: str, change: str, filepath: str,
+               contents: str) -> Dict[str, Any]:
+  """Attaches file modifications to an open change.
+
+  Args:
+    host: The Gerrit host to interact with.
+    change: A Gerrit change number.
+    filepath: Path of the file in the repo to modify.
+    contents: New contents of the file.
+
+  Returns:
+    A JSON response dict.
+  """
+  path = '%s/edit/%s' % (
+      _GetChangePath(change), urllib.parse.quote(filepath, ''))
+  contents = contents.encode('utf-8')  # string -> bytes
+  contents = base64.b64encode(contents)  # bytes -> bytes
+  contents = contents.decode('utf-8')  # bytes -> string
+  body = {
+      'binary_content': 'data:text/plain;base64,%s' % contents
+  }
+  try:
+    return FetchUrlJson(host, path, body=body, reqtype='PUT', ignore_204=True)
+  except GOBError as e:
+    if e.http_status != 204:
+      raise
+
+
+def PublishChangeEdit(host: str, change: str) -> Dict[str, Any]:
+  """Publishes any open edits in a change.
+
+  Args:
+    host: The Gerrit host to interact with.
+    change: A Gerrit change number.
+
+  Returns:
+    A JSON response dict.
+  """
+  path = '%s/edit:publish' % _GetChangePath(change)
+  body = {'notify': 'NONE'}
+  try:
+    return FetchUrlJson(host, path, body=body, reqtype='POST', ignore_204=True)
+  except GOBError as e:
+    if e.http_status != 204:
+      raise
+
+
 def ReviewedChange(host, change):
   """Mark a gerrit change as reviewed."""
   path = '%s/reviewed' % _GetChangePath(change)
@@ -676,6 +745,57 @@
   return FetchUrlJson(host, path, reqtype='POST', body=body, ignore_404=False)
 
 
+def GetAttentionSet(host: str, change: str) -> Optional[Dict[str, Any]]:
+  """Get information about the attention set of a change.
+
+  Args:
+    host: The Gerrit host to interact with.
+    change: The Gerrit change ID.
+
+  Returns:
+    A JSON response dict.
+  """
+  path = '%s/attention' % _GetChangePath(change)
+  return FetchUrlJson(host, path)
+
+
+def AddAttentionSet(host: str, change: str, add: Tuple[str, ...], reason: str,
+                    notify: str = '') -> Optional[Dict[str, Any]]:
+  """Add users to the attention set of a change."""
+  if not add:
+    return
+  body = {}
+  body['reason'] = reason
+  if notify:
+    body['notify'] = notify
+  path = '%s/attention' % _GetChangePath(change)
+  for r in add:
+    body['user'] = r
+    jmsg = FetchUrlJson(host, path, reqtype='POST', body=body, ignore_404=False)
+  # Return the last response. We've run through at least one request if we got
+  # here.
+  return jmsg
+
+
+def RemoveAttentionSet(host: str, change: str, remove: Tuple[str, ...],
+                       reason: str, notify: str = ''):
+  """Remove users from the attention set of a change."""
+  if not remove:
+    return
+  body = {}
+  body['reason'] = reason
+  if notify:
+    body['notify'] = notify
+  for r in remove:
+    path = '%s/attention/%s/delete' % (_GetChangePath(change), r)
+    try:
+      FetchUrl(host, path, reqtype='POST', body=body, ignore_204=True)
+    except GOBError as e:
+      # On success, gerrit returns status 204; anything else is an error.
+      if e.http_status != 204:
+        raise
+
+
 def GetReviewers(host, change):
   """Get information about all reviewers attached to a change.
 
@@ -846,6 +966,25 @@
     raise GOBError(reason=msg)
 
 
+def GetFileContentsOnHead(git_url: str, filepath: str) -> str:
+  """Returns the current contents of a file on the default branch.
+
+  Retrieves the contents from Gitiles via its API, not Gerrit's.
+
+  Args:
+    git_url: URL for the repository to get the file contents from.
+    filepath: Path of the file in the repository.
+
+  Returns:
+    The contents of the file as a string.
+  """
+  parsed_url = urllib.parse.urlparse(git_url)
+  path = parsed_url[2].rstrip('/') + f'/+/HEAD/{filepath}?format=TEXT'
+  contents = FetchUrl(parsed_url[1], path, ignore_404=False)
+  contents = base64.b64decode(contents)
+  return contents.decode('utf-8')
+
+
 def GetCommitDate(git_url, commit):
   """Returns the date of a particular git commit.
 
diff --git a/lib/gob_util_unittest.py b/lib/gob_util_unittest.py
index fb574ef..fc47dee 100644
--- a/lib/gob_util_unittest.py
+++ b/lib/gob_util_unittest.py
@@ -4,7 +4,9 @@
 
 """Unittests for gob_util.py"""
 
+import base64
 import http.client
+import json
 import tempfile
 import time
 
@@ -45,23 +47,6 @@
     return tuple(self.headers.items())
 
 
-class FakeHTTPConnection(object):
-  """Enough of a HTTPConnection result for FetchUrl."""
-
-  def __init__(self, req_url='/', req_method='GET', req_headers=None,
-               req_body=None, **kwargs):
-    self.kwargs = kwargs.copy()
-    self.req_params = {
-        'url': req_url,
-        'method': req_method,
-        'headers': req_headers,
-        'body': req_body,
-    }
-
-  def getresponse(self):
-    return FakeHTTPResponse(**self.kwargs)
-
-
 class GobTest(cros_test_lib.MockTestCase):
   """Unittests that use mocks."""
 
@@ -72,11 +57,11 @@
 
   def testUtf8Response(self):
     """Handle gerrit responses w/UTF8 in them."""
-    self.conn.return_value = FakeHTTPConnection(body=self.UTF8_DATA)
+    self.conn.return_value = FakeHTTPResponse(body=self.UTF8_DATA)
     gob_util.FetchUrl('', '')
 
   def testUtf8Response502(self):
-    self.conn.return_value = FakeHTTPConnection(body=self.UTF8_DATA, status=502)
+    self.conn.return_value = FakeHTTPResponse(body=self.UTF8_DATA, status=502)
 
     with self.assertRaises(gob_util.InternalGOBError):
       gob_util.FetchUrl('', '')
@@ -124,6 +109,32 @@
     ep.close()
     self.assertEqual(expected_parsed_data, ep.ParsedDiv())
 
+  def testCreateChange(self):
+    body = json.dumps({'change_num': 123456}).encode()
+    xss_protection_prefix = b")]}'\n"
+    body = xss_protection_prefix + body
+    self.conn.return_value = FakeHTTPResponse(body=body, status=200)
+    change_json = gob_util.CreateChange(
+        'some.git.url', 'project', 'branch', 'subject', True)
+    self.assertEqual(change_json['change_num'], 123456)
+
+  def testChangeEdit(self):
+    self.conn.return_value = FakeHTTPResponse(body={}, status=204)
+    gob_util.ChangeEdit('some.git.url', 123456, 'some/file/path',
+                        'some file contents')
+
+  def testPublishChangeEdit(self):
+    self.conn.return_value = FakeHTTPResponse(body={}, status=204)
+    gob_util.PublishChangeEdit('some.git.url', 123456)
+
+  def testGetFileContents(self):
+    expected_contents = 'some file contents'
+    body = base64.b64encode(expected_contents.encode())
+    self.conn.return_value = FakeHTTPResponse(body=body, status=200)
+    contents = gob_util.GetFileContentsOnHead('some.git.url',
+                                              'some/file/path')
+    self.assertEqual(contents, expected_contents)
+
 
 class GetCookieTests(cros_test_lib.TestCase):
   """Unittests for GetCookies()"""
diff --git a/lib/gs.py b/lib/gs.py
index c6ef1ef..306cf18 100644
--- a/lib/gs.py
+++ b/lib/gs.py
@@ -322,7 +322,7 @@
   # (1*sleep) the first time, then (2*sleep), continuing via attempt * sleep.
   DEFAULT_SLEEP_TIME = 60
 
-  GSUTIL_VERSION = '4.60'
+  GSUTIL_VERSION = '5.4'
   GSUTIL_TAR = 'gsutil_%s.tar.gz' % GSUTIL_VERSION
   GSUTIL_URL = (PUBLIC_BASE_HTTPS_URL +
                 'chromeos-mirror/gentoo/distfiles/%s' % GSUTIL_TAR)
@@ -365,6 +365,8 @@
       b'socket.error: [Errno 104] Connection reset by peer',
       b'Received bad request from server',
       b"can't start new thread",
+      # See: b/197574857.
+      b'OSError: None',
   )
 
   @classmethod
@@ -1301,9 +1303,12 @@
       # raising errors internally like other commands), we have to look
       # for errors ourselves.  See the related bug report here:
       # https://github.com/GoogleCloudPlatform/gsutil/issues/288
-      # Example line:
+      # Example lines:
       # No URLs matched gs://bucket/file
-      if e.result.error and e.result.error.startswith('No URLs matched'):
+      # Some more msg: No URLs matched gs://bucket/file
+      if (e.result.error and
+          any(x.startswith('No URLs matched')
+              for x in e.result.error.splitlines())):
         raise GSNoSuchKey('Stat Error: No URLs matched %s.' % path)
 
       # No idea what this is, so just choke.
diff --git a/lib/gs_unittest.py b/lib/gs_unittest.py
index 2dc7ea9..9c10ba6 100644
--- a/lib/gs_unittest.py
+++ b/lib/gs_unittest.py
@@ -1386,6 +1386,10 @@
 
   # When stat throws an error.  It's a special snow flake.
   STAT_ERROR_OUTPUT = b'No URLs matched gs://abc/1'
+  RETRY_STAT_ERROR_OUTPUT = (
+      b'Retrying request, attempt #1...\nNo URLs matched gs://abc/1'
+  )
+
 
   def testStat(self):
     """Test ability to get the generation of a file."""
@@ -1450,6 +1454,15 @@
     self.assertRaises(gs.GSNoSuchKey, ctx.Stat, 'gs://abc/1')
     self.gs_mock.assertCommandContains(['stat', '--', 'gs://abc/1'])
 
+  def testStatRetryNoExist(self):
+    """Test ability to get the generation of a file."""
+    self.gs_mock.AddCmdResult(['stat', '--', 'gs://abc/1'],
+                              error=self.RETRY_STAT_ERROR_OUTPUT,
+                              returncode=1)
+    ctx = gs.GSContext()
+    self.assertRaises(gs.GSNoSuchKey, ctx.Stat, 'gs://abc/1')
+    self.gs_mock.assertCommandContains(['stat', '--', 'gs://abc/1'])
+
 
 class UnmockedStatTest(cros_test_lib.TempDirTestCase):
   """Tests Stat functionality w/out mocks."""
diff --git a/lib/kernel_builder.py b/lib/kernel_builder.py
index a24765c..03d37e0 100644
--- a/lib/kernel_builder.py
+++ b/lib/kernel_builder.py
@@ -194,7 +194,7 @@
       cmd += ['--noenable_rootfs_verification']
     if boot_args:
       arg_list = kernel_cmdline.KernelArgList(boot_args)
-      cmd += [f'--boot_args="{arg_list.Format()}"']
+      cmd += [f'--boot_args={arg_list.Format()}']
     if serial:
       if not serial.startswith('tty'):
         raise KernelBuildError('Possibly invalid argument for serial port: %s' %
diff --git a/lib/kernel_builder_unittest.py b/lib/kernel_builder_unittest.py
index e66d7ed..a95581d 100644
--- a/lib/kernel_builder_unittest.py
+++ b/lib/kernel_builder_unittest.py
@@ -29,21 +29,21 @@
 
     emerge_board = 'emerge-foo-board'
     extra_env = {
-      'PKGDIR': os.path.join('foo-tmp', 'packages'),
-      'USE': 'z x y'
+        'PKGDIR': os.path.join('foo-tmp', 'packages'),
+        'USE': 'z x y'
     }
     self.assertCommandCalled(
-      [emerge_board, 'chromeos-base/chromeos-initramfs'],
-      enter_chroot=True, extra_env=extra_env)
+        [emerge_board, 'chromeos-base/chromeos-initramfs'],
+        enter_chroot=True, extra_env=extra_env)
     self.assertCommandCalled(
-      [emerge_board, '--onlydeps', 'kernel'],
-      enter_chroot=True, extra_env=extra_env)
+        [emerge_board, '--onlydeps', 'kernel'],
+        enter_chroot=True, extra_env=extra_env)
     self.assertCommandCalled(
-      [emerge_board, '--buildpkgonly', 'kernel'],
-      enter_chroot=True, extra_env=extra_env)
+        [emerge_board, '--buildpkgonly', 'kernel'],
+        enter_chroot=True, extra_env=extra_env)
     self.assertCommandCalled(
-      [emerge_board, '--usepkgonly', '--root=foo-root', 'kernel'],
-      enter_chroot=True, extra_env=extra_env)
+        [emerge_board, '--usepkgonly', '--root=foo-root', 'kernel'],
+        enter_chroot=True, extra_env=extra_env)
 
   def testCreateCustomKernelOverrideUseFlag(self):
     """Tests CreateCustomKernel()."""
@@ -55,21 +55,21 @@
 
     emerge_board = 'emerge-foo-board'
     extra_env = {
-      'PKGDIR': os.path.join('foo-tmp', 'packages'),
-      'USE': 'foo x y'
+        'PKGDIR': os.path.join('foo-tmp', 'packages'),
+        'USE': 'foo x y'
     }
     self.assertCommandCalled(
-      [emerge_board, 'chromeos-base/chromeos-initramfs'],
-      enter_chroot=True, extra_env=extra_env)
+        [emerge_board, 'chromeos-base/chromeos-initramfs'],
+        enter_chroot=True, extra_env=extra_env)
     self.assertCommandCalled(
-      [emerge_board, '--onlydeps', 'kernel'],
-      enter_chroot=True, extra_env=extra_env)
+        [emerge_board, '--onlydeps', 'kernel'],
+        enter_chroot=True, extra_env=extra_env)
     self.assertCommandCalled(
-      [emerge_board, '--buildpkgonly', 'kernel'],
-      enter_chroot=True, extra_env=extra_env)
+        [emerge_board, '--buildpkgonly', 'kernel'],
+        enter_chroot=True, extra_env=extra_env)
     self.assertCommandCalled(
-      [emerge_board, '--usepkgonly', '--root=foo-root', 'kernel'],
-      enter_chroot=True, extra_env=extra_env)
+        [emerge_board, '--usepkgonly', '--root=foo-root', 'kernel'],
+        enter_chroot=True, extra_env=extra_env)
 
   def testCreateKernelImageDefaultArgs(self):
     """Tests CreateKernelImage() with default arguments."""
@@ -120,6 +120,6 @@
         f'--private={constants.RECOVERY_DATA_PRIVATE_KEY}',
         f'--keyblock={constants.RECOVERY_KEYBLOCK}',
         '--noenable_rootfs_verification',
-        '--boot_args="x y=foo"',
+        '--boot_args=x y=foo',
         '--enable_serial=ttyfoo',
     ], enter_chroot=True)
diff --git a/lib/locking.py b/lib/locking.py
index b991e50..bca611c 100644
--- a/lib/locking.py
+++ b/lib/locking.py
@@ -40,7 +40,7 @@
     yield
 
 
-class _Lock(cros_build_lib.MasterPidContextManager):
+class _Lock(cros_build_lib.PrimaryPidContextManager):
   """Base lockf based locking.  Derivatives need to override _GetFd"""
 
   def __init__(self, description=None, verbose=True, locktype=LOCKF,
@@ -69,7 +69,7 @@
       blocking: If True, use a blocking lock.
       blocking_timeout: If not None, time is seconds to wait on blocking calls.
     """
-    cros_build_lib.MasterPidContextManager.__init__(self)
+    cros_build_lib.PrimaryPidContextManager.__init__(self)
     self._verbose = verbose
     self.description = description
     self._fd = None
diff --git a/lib/minios.py b/lib/minios.py
index c19bc10..7533bd3 100644
--- a/lib/minios.py
+++ b/lib/minios.py
@@ -13,7 +13,7 @@
 from chromite.lib import image_lib
 from chromite.lib import kernel_builder
 
-
+CROS_DEBUG_FLAG = 'cros_debug'
 MINIOS_KERNEL_IMAGE = 'minios_vmlinuz.image'
 KERNEL_FLAGS = ['minios', 'minios_ramfs', 'tpm', 'i2cdev', 'vfat',
                 'kernel_compress_xz', 'pcserial', '-kernel_afdo']
@@ -32,7 +32,8 @@
 def CreateMiniOsKernelImage(board: str, version: str, work_dir: str,
                             keys_dir: str, public_key: str,
                             private_key: str, keyblock: str,
-                            serial: str) -> str:
+                            serial: str, build_kernel: bool = True,
+                            developer_mode: bool = False) -> str:
   """Creates the MiniOS kernel image.
 
   And puts it in the work directory.
@@ -48,20 +49,25 @@
                  the keyblock.
     keyblock: Filename to the kernel keyblock.
     serial: Serial port for the kernel console (e.g. printks).
+    build_kernel: Build a new kernel from source.
+    developer_mode: Add developer mode flags to the kernel image.
 
   Returns:
     The path to the generated kernel image.
   """
   install_root = os.path.join(
-    (build_target_lib.get_default_sysroot_path(board)), 'factory-root')
+      (build_target_lib.get_default_sysroot_path(board)), 'factory-root')
   kb = kernel_builder.Builder(board, work_dir, install_root)
-  # MiniOS ramfs cannot be built with multiple conflicting `_ramfs` flags.
-  kb.CreateCustomKernel(KERNEL_FLAGS,
-                        [x for x in os.environ.get('USE', '').split()
-                         if not x.endswith('_ramfs')])
+  if build_kernel:
+    # MiniOS ramfs cannot be built with multiple conflicting `_ramfs` flags.
+    kb.CreateCustomKernel(KERNEL_FLAGS,
+                          [x for x in os.environ.get('USE', '').split()
+                           if not x.endswith('_ramfs')])
   kernel = os.path.join(work_dir, MINIOS_KERNEL_IMAGE)
   assert ' ' not in version, f'bad version: {version}'
   boot_args = f'noinitrd panic=60 cros_minios_version={version} cros_minios'
+  if developer_mode:
+    boot_args += f' {CROS_DEBUG_FLAG}'
   kb.CreateKernelImage(kernel, boot_args=boot_args,
                        serial=serial, keys_dir=keys_dir, public_key=public_key,
                        private_key=private_key, keyblock=keyblock)
diff --git a/lib/minios_unittest.py b/lib/minios_unittest.py
index f1808ca..275544c 100644
--- a/lib/minios_unittest.py
+++ b/lib/minios_unittest.py
@@ -18,7 +18,7 @@
   """Tests Builder."""
 
   FAKE_PARTITIONS = (
-    image_lib.PartitionInfo(9, 10, 10+512*4, 512*4, 'fs', 'MINIOS-A', ''),
+      image_lib.PartitionInfo(9, 10, 10+512*4, 512*4, 'fs', 'MINIOS-A', ''),
   )
 
   def setUp(self):
@@ -43,8 +43,8 @@
                                    'foo-private-key', 'foo-keyblock',
                                    'foo-tty')
     bck_mock.assert_called_once_with(
-      ['minios', 'minios_ramfs', 'tpm', 'i2cdev', 'vfat',
-       'kernel_compress_xz', 'pcserial', '-kernel_afdo'], [])
+        ['minios', 'minios_ramfs', 'tpm', 'i2cdev', 'vfat',
+         'kernel_compress_xz', 'pcserial', '-kernel_afdo'], [])
     bki_mock.assert_called_once_with(
         os.path.join(self.tempdir,
                      minios.MINIOS_KERNEL_IMAGE),
@@ -66,9 +66,9 @@
                                    'foo-private-key', 'foo-keyblock',
                                    'foo-tty')
     bck_mock.assert_called_once_with(
-      ['minios', 'minios_ramfs', 'tpm', 'i2cdev', 'vfat',
-       'kernel_compress_xz', 'pcserial', '-kernel_afdo'],
-      ['foo', 'bar'])
+        ['minios', 'minios_ramfs', 'tpm', 'i2cdev', 'vfat',
+         'kernel_compress_xz', 'pcserial', '-kernel_afdo'],
+        ['foo', 'bar'])
     bki_mock.assert_called_once_with(
         os.path.join(self.tempdir,
                      minios.MINIOS_KERNEL_IMAGE),
@@ -77,6 +77,50 @@
         keys_dir='foo-keys-dir', public_key='foo-public-key',
         private_key='foo-private-key', keyblock='foo-keyblock')
 
+  def testCreateMiniOsKernelImageDeveloperMode(self):
+    """Tests CreateMiniOsKernelImage() with developer mode enabled."""
+    self.PatchObject(os.environ, 'get', return_value='')
+    bck_mock = self.PatchObject(kernel_builder.Builder,
+                                'CreateCustomKernel')
+    bki_mock = self.PatchObject(kernel_builder.Builder,
+                                'CreateKernelImage')
+
+    minios.CreateMiniOsKernelImage('foo-board', '0.0.0.0', self.tempdir,
+                                   'foo-keys-dir', 'foo-public-key',
+                                   'foo-private-key', 'foo-keyblock',
+                                   'foo-tty', developer_mode=True)
+    bck_mock.assert_called_once_with(
+        ['minios', 'minios_ramfs', 'tpm', 'i2cdev', 'vfat',
+         'kernel_compress_xz', 'pcserial', '-kernel_afdo'], [])
+    bki_mock.assert_called_once_with(
+        os.path.join(self.tempdir,
+                     minios.MINIOS_KERNEL_IMAGE),
+        boot_args='noinitrd panic=60 cros_minios_version=0.0.0.0 cros_minios'
+        ' cros_debug', serial='foo-tty',
+        keys_dir='foo-keys-dir', public_key='foo-public-key',
+        private_key='foo-private-key', keyblock='foo-keyblock')
+
+  def testCreateMiniOsKernelImageBuildDisabled(self):
+    """Tests CreateMiniOsKernelImage() with kernel build disabled."""
+    self.PatchObject(os.environ, 'get', return_value='')
+    bck_mock = self.PatchObject(kernel_builder.Builder,
+                                'CreateCustomKernel')
+    bki_mock = self.PatchObject(kernel_builder.Builder,
+                                'CreateKernelImage')
+
+    minios.CreateMiniOsKernelImage('foo-board', '0.0.0.0', self.tempdir,
+                                   'foo-keys-dir', 'foo-public-key',
+                                   'foo-private-key', 'foo-keyblock',
+                                   'foo-tty', False, True)
+    bck_mock.assert_not_called()
+    bki_mock.assert_called_once_with(
+        os.path.join(self.tempdir,
+                     minios.MINIOS_KERNEL_IMAGE),
+        boot_args='noinitrd panic=60 cros_minios_version=0.0.0.0 cros_minios'
+        ' cros_debug', serial='foo-tty',
+        keys_dir='foo-keys-dir', public_key='foo-public-key',
+        private_key='foo-private-key', keyblock='foo-keyblock')
+
   def testInsertMiniOsKernelImage(self):
     """Tests InsertMiniOsKernelImage()."""
     kernel_path = os.path.join(self.tempdir,
diff --git a/lib/osutils.py b/lib/osutils.py
index 57991e5..228d6be 100644
--- a/lib/osutils.py
+++ b/lib/osutils.py
@@ -393,7 +393,7 @@
 
 
 def SafeUnlink(path: Union[Path, str],
-              sudo: bool = False):
+               sudo: bool = False):
   """Unlink a file from disk, ignoring if it doesn't exist.
 
   Returns:
@@ -963,6 +963,7 @@
 
 
 # Flags synced from sys/mount.h.  See mount(2) for details.
+# COIL(b/187793358): keeping values synced with Linux utility constants.
 MS_RDONLY = 1
 MS_NOSUID = 2
 MS_NODEV = 4
@@ -1037,7 +1038,8 @@
                 _MaybeEncode(fstype), ctypes.c_int(flags),
                 _MaybeEncode(data)) != 0:
     e = ctypes.get_errno()
-    raise OSError(e, os.strerror(e))
+    raise OSError(e, 'Could not mount "%s" to "%s": %s' %
+                  (source, target, os.strerror(e)))
 
 
 def MountDir(src_path, dst_path, fs_type=None, sudo=True, makedirs=True,
@@ -1153,7 +1155,7 @@
   os.environ.update(env)
 
 
-def SourceEnvironment(script, whitelist, ifs=',', env=None, multiline=False):
+def SourceEnvironment(script, allowlist, ifs=',', env=None, multiline=False):
   """Returns the environment exported by a shell script.
 
   Note that the script is actually executed (sourced), so do not use this on
@@ -1162,19 +1164,19 @@
 
   Args:
     script: The shell script to 'source'.
-    whitelist: An iterable of environment variables to retrieve values for.
+    allowlist: An iterable of environment variables to retrieve values for.
     ifs: When showing arrays, what separator to use.
     env: A dict of the initial env to pass down.  You can also pass it None
          (to clear the env) or True (to preserve the current env).
     multiline: Allow a variable to span multiple lines.
 
   Returns:
-    A dictionary containing the values of the whitelisted environment
+    A dictionary containing the values of the allowlisted environment
     variables that are set.
   """
   dump_script = ['source "%s" >/dev/null' % script,
                  'IFS="%s"' % ifs]
-  for var in whitelist:
+  for var in allowlist:
     # Note: If we want to get more exact results out of bash, we should switch
     # to using `declare -p "${var}"`.  It would require writing a custom parser
     # here, but it would be more robust.
diff --git a/lib/osutils_unittest.py b/lib/osutils_unittest.py
index 9be8b9c..aafc29e 100644
--- a/lib/osutils_unittest.py
+++ b/lib/osutils_unittest.py
@@ -837,7 +837,7 @@
 class SourceEnvironmentTest(cros_test_lib.TempDirTestCase):
   """Test osutil's environmental variable related methods."""
 
-  ENV_WHITELIST = {
+  ENV_ALLOWLIST = {
       'ENV1': 'monkeys like bananas',
       'ENV3': 'merci',
       'ENV6': '',
@@ -868,10 +868,10 @@
     osutils.WriteFile(self.env_file, self.ENV)
     osutils.WriteFile(self.env_file_multiline, self.ENV_MULTILINE)
 
-  def testWhiteList(self):
+  def testAllowList(self):
     env_dict = osutils.SourceEnvironment(
         self.env_file, ('ENV1', 'ENV3', 'ENV5', 'ENV6'))
-    self.assertEqual(env_dict, self.ENV_WHITELIST)
+    self.assertEqual(env_dict, self.ENV_ALLOWLIST)
 
   def testArrays(self):
     env_dict = osutils.SourceEnvironment(self.env_file, ('ENVA',))
diff --git a/lib/parallel.py b/lib/parallel.py
index 6306739..332be22 100644
--- a/lib/parallel.py
+++ b/lib/parallel.py
@@ -61,6 +61,49 @@
   signal.signal(signal.SIGTERM, signal.SIG_IGN)
 
 
+def WrapMultiprocessing(callback, *args, **kwargs):
+  """Wraps a callback with a short value of TMPDIR.
+
+  This is intended to wrap calls to multiprocessing to ensure any sockets
+  created during initialization are created under the /tmp tree rather than in a
+  custom temp directory. This is needed because TMPDIR might be really long, and
+  named sockets are limited to 108 characters.
+
+  Examples:
+    errors = WrapMultiprocessing(multiprocessing.Value, 'i')
+
+  Returns:
+    The return value of the callback function with the specified args
+  """
+  # Use a short directory in /tmp. Do not use /tmp directly to keep these
+  # temporary files together and because certain environments do not like too
+  # many top-level paths in /tmp (see crbug.com/945523).
+  # Make it mode 1777 to mirror /tmp, so that we don't have failures when root
+  # calls parallel first, and some other user calls it later.
+  tmp_dir = '/tmp/chromite.parallel.%d' % os.geteuid()
+  osutils.SafeMakedirs(tmp_dir, mode=0o1777)
+  old_tempdir_value, old_tempdir_env = osutils.SetGlobalTempDir(tmp_dir)
+  try:
+    return callback(*args, **kwargs)
+  finally:
+    osutils.SetGlobalTempDir(old_tempdir_value, old_tempdir_env)
+
+
+def _get_sync_manager():
+  """Create a SyncManager for use in Manager below
+
+  This is put into a helper function so it can be used inside
+  WrapMultiprocessing to adjust TMPDIR to avoid paths too long for UNIX sockets.
+  """
+  m = HackTimeoutSyncManager()
+  # SyncManager doesn't handle KeyboardInterrupt exceptions well; pipes get
+  # broken and E_NOENT or E_PIPE errors are thrown from various places. We
+  # can just ignore SIGINT in the SyncManager and things will close properly
+  # when the enclosing with-statement exits.
+  m.start(IgnoreSigintAndSigterm)
+  return m
+
+
 def Manager():
   """Create a background process for managing interprocess communication.
 
@@ -77,24 +120,7 @@
   Returns:
     The return value of multiprocessing.Manager()
   """
-  # Use a short directory in /tmp. Do not use /tmp directly to keep these
-  # temperary files together and because certain environments do not like too
-  # many top-level paths in /tmp (see crbug.com/945523).
-  # Make it mode 1777 to mirror /tmp, so that we don't have failures when root
-  # calls parallel first, and some other user calls it later.
-  tmp_dir = '/tmp/chromite.parallel.%d' % os.geteuid()
-  osutils.SafeMakedirs(tmp_dir, mode=0o1777)
-  old_tempdir_value, old_tempdir_env = osutils.SetGlobalTempDir(tmp_dir)
-  try:
-    m = HackTimeoutSyncManager()
-    # SyncManager doesn't handle KeyboardInterrupt exceptions well; pipes get
-    # broken and E_NOENT or E_PIPE errors are thrown from various places. We
-    # can just ignore SIGINT in the SyncManager and things will close properly
-    # when the enclosing with-statement exits.
-    m.start(IgnoreSigintAndSigterm)
-    return m
-  finally:
-    osutils.SetGlobalTempDir(old_tempdir_value, old_tempdir_env)
+  return WrapMultiprocessing(_get_sync_manager)
 
 
 class BackgroundFailure(failures_lib.CompoundFailure):
diff --git a/lib/path_util.py b/lib/path_util.py
index d5f8265..6994861 100644
--- a/lib/path_util.py
+++ b/lib/path_util.py
@@ -34,26 +34,37 @@
     source_path: Value to override default source root inference.
     source_from_path_repo: Whether to infer the source root from the converted
       path's repo parent during inbound translation; overrides |source_path|.
+    chroot_path: Full path of the chroot to use. If chroot_path is specified,
+      source_path cannot be specified.
   """
 
-  # TODO(garnold) We currently infer the source root based on the path's own
-  # encapsulating repository. This is a heuristic catering to paths are being
-  # translated to be used in a chroot that's not associated with the currently
-  # executing code (for example, cbuildbot run on a build root or a foreign
-  # tree checkout). This approach might result in arbitrary repo-contained
-  # paths being translated to invalid chroot paths where they actually should
-  # not, and other valid source paths failing to translate because they are not
-  # repo-contained. Eventually we'll want to make this behavior explicit, by
-  # either passing a source_root value, or requesting to infer it from the path
-  # (source_from_path_repo=True), but otherwise defaulting to the executing
-  # code's source root in the normal case. When that happens, we'll be
-  # switching source_from_path_repo to False by default. See chromium:485746.
+  # When chroot_path is specified, it is assumed that any reference to
+  # the chroot mount point (/mnt/host/source) points back to the
+  # inferred source root determined by constants.SOURCE_ROOT. For example,
+  # assuming:
+  #   constants.SOURCE_ROOT == /workspace/checkout/
+  # and
+  #   chroot_path = /custom/chroot/path :
+  #
+  # FromChroot('/mnt/host/source/my/file') -> /workspace/checkout/my/file
+  # FromChroot('/some/other/file') -> /custom/chroot/path/some/other/file
+  # ToChroot('/workspace/checkout/file') -> /mnt/host/source/file
+  # ToChroot('/custom/checkout/chroot/this/file') -> /this/file
 
-  def __init__(self, source_path=None, source_from_path_repo=True):
+  def __init__(self, source_path=None, source_from_path_repo=True,
+               chroot_path=None):
+    if chroot_path and source_path:
+      raise AssertionError(
+          'Either source_path or chroot_path must be specified')
     self._inside_chroot = cros_build_lib.IsInsideChroot()
+    self._source_from_path_repo = source_from_path_repo
+    self._custom_chroot_path = chroot_path
     self._source_path = (constants.SOURCE_ROOT if source_path is None
                          else source_path)
-    self._source_from_path_repo = source_from_path_repo
+    if chroot_path and self._TranslatePath(chroot_path, self._source_path, ''):
+      raise AssertionError(
+          f'chroot_path {chroot_path} must not be in'
+          f'the source path {self._source_path}')
 
     # The following are only needed if outside the chroot.
     if self._inside_chroot:
@@ -61,7 +72,8 @@
       self._chroot_link = None
       self._chroot_to_host_roots = None
     else:
-      self._chroot_path = self._GetSourcePathChroot(self._source_path)
+      self._chroot_path = self._GetSourcePathChroot(self._source_path,
+                                                    self._custom_chroot_path)
       # The chroot link allows us to resolve paths when the chroot is symlinked
       # to the default location. This is generally not used, but it is useful
       # for CI for optimization purposes. We will trust them not to do something
@@ -81,8 +93,10 @@
     """Returns the cache directory."""
     return os.path.realpath(GetCacheDir())
 
-  def _GetSourcePathChroot(self, source_path):
+  def _GetSourcePathChroot(self, source_path, custom_chroot_path=None):
     """Returns path to the chroot directory of a given source root."""
+    if custom_chroot_path:
+      return custom_chroot_path
     if source_path is None:
       return None
     return os.path.join(source_path, constants.DEFAULT_CHROOT_DIR)
@@ -163,7 +177,7 @@
     chroot_path = self._chroot_path
     chroot_link = self._chroot_link
 
-    if self._source_from_path_repo:
+    if self._custom_chroot_path is None and self._source_from_path_repo:
       path_repo_dir = git.FindRepoDir(path)
       if path_repo_dir is not None:
         source_path = os.path.abspath(os.path.join(path_repo_dir, '..'))
@@ -333,12 +347,13 @@
   return os.environ.get(constants.SHARED_CACHE_ENVVAR, FindCacheDir())
 
 
-def ToChrootPath(path, source_path=None):
+def ToChrootPath(path, source_path=None, chroot_path=None):
   """Resolves current environment |path| for use in the chroot.
 
   Args:
     path: string path to translate into chroot namespace.
     source_path: string path to root of source checkout with chroot in it.
+    chroot_path: string name of the full chroot path to use.
 
   Returns:
     The same path converted to "inside chroot" namespace.
@@ -346,20 +361,23 @@
   Raises:
     ValueError: If the path references a location not available in the chroot.
   """
-  return ChrootPathResolver(source_path=source_path).ToChroot(path)
+  return ChrootPathResolver(source_path=source_path,
+                            chroot_path=chroot_path).ToChroot(path)
 
 
-def FromChrootPath(path, source_path=None):
+def FromChrootPath(path, source_path=None, chroot_path=None):
   """Resolves chroot |path| for use in the current environment.
 
   Args:
     path: string path to translate out of chroot namespace.
     source_path: string path to root of source checkout with chroot in it.
+    chroot_path: string name of the full chroot path to use
 
   Returns:
     The same path converted to "outside chroot" namespace.
   """
-  return ChrootPathResolver(source_path=source_path).FromChroot(path)
+  return ChrootPathResolver(source_path=source_path,
+                            chroot_path=chroot_path).FromChroot(path)
 
 
 def normalize_paths_to_source_root(
diff --git a/lib/path_util_unittest.py b/lib/path_util_unittest.py
index 7c6d161..0ad3af8 100644
--- a/lib/path_util_unittest.py
+++ b/lib/path_util_unittest.py
@@ -20,7 +20,7 @@
 FAKE_SOURCE_PATH = '/path/to/source/tree'
 FAKE_REPO_PATH = '/path/to/repo'
 CUSTOM_SOURCE_PATH = '/custom/source/path'
-
+CUSTOM_CHROOT_PATH = '/custom/chroot/path'
 
 class DetermineCheckoutTest(cros_test_lib.MockTempDirTestCase):
   """Verify functionality for figuring out what checkout we're in."""
@@ -168,9 +168,23 @@
   def FakeCwd(self, base_path):
     return os.path.join(base_path, 'somewhere/in/there')
 
-  def SetChrootPath(self, source_path):
+  def SetChrootPath(self, source_path, chroot_path=None):
     """Set and fake the chroot path."""
-    self.chroot_path = os.path.join(source_path, constants.DEFAULT_CHROOT_DIR)
+    self.chroot_path = chroot_path or os.path.join(source_path,
+                                                   constants.DEFAULT_CHROOT_DIR)
+
+  def testResolverInit(self):
+    """Test class initiation errors"""
+
+    # Case: source_path and chroot_path are mutually exclusive
+    with self.assertRaises(AssertionError):
+      path_util.ChrootPathResolver(source_path=constants.SOURCE_ROOT,
+                                   chroot_path=CUSTOM_CHROOT_PATH)
+
+    # Case: chroot_path cannot be part of inferred source root path
+    with self.assertRaises(AssertionError):
+      path_util.ChrootPathResolver(
+          chroot_path=os.path.join(constants.SOURCE_ROOT, 'dir'))
 
   @mock.patch('chromite.lib.cros_build_lib.IsInsideChroot', return_value=True)
   def testInsideChroot(self, _):
@@ -249,9 +263,31 @@
         resolver.ToChroot('/some/path')
 
   @mock.patch('chromite.lib.cros_build_lib.IsInsideChroot', return_value=False)
+  def testOutsideCustomChrootInbound(self, _):
+    """Tests ToChroot() calls from outside a custom chroot."""
+
+    self.SetChrootPath(constants.SOURCE_ROOT, CUSTOM_CHROOT_PATH)
+    resolver = path_util.ChrootPathResolver(chroot_path=CUSTOM_CHROOT_PATH)
+
+    # Case: path inside the chroot space.
+    self.assertEqual(
+        '/some/path',
+        resolver.ToChroot(os.path.join(self.chroot_path, 'some/path')))
+
+    # Case: path from source root
+    self.assertEqual(
+        os.path.join(constants.CHROOT_SOURCE_ROOT, 'some/path'),
+        resolver.ToChroot(os.path.join(constants.SOURCE_ROOT, 'some/path')))
+
+    # Case: not mapped to chroot
+    with self.assertRaises(ValueError):
+      resolver.ToChroot('/random/file')
+
+  @mock.patch('chromite.lib.cros_build_lib.IsInsideChroot', return_value=False)
   def testOutsideChrootOutbound(self, _):
     """Tests FromChroot() calls from outside the chroot."""
     self.PatchObject(os, 'getcwd', return_value=self.FakeCwd(FAKE_SOURCE_PATH))
+
     self.SetChrootPath(constants.SOURCE_ROOT)
     resolver = path_util.ChrootPathResolver()
     # These two patches are only necessary or have any affect on the test when
@@ -293,6 +329,56 @@
         resolver.FromChroot('/some/path'))
 
   @mock.patch('chromite.lib.cros_build_lib.IsInsideChroot', return_value=False)
+  def testOutsideCustomChrootOutbound(self, _):
+    """Tests FromChroot() calls from outside the chroot."""
+    self.PatchObject(os, 'getcwd', return_value=self.FakeCwd(FAKE_SOURCE_PATH))
+
+    self.SetChrootPath(constants.SOURCE_ROOT, chroot_path=CUSTOM_CHROOT_PATH)
+    resolver = path_util.ChrootPathResolver(chroot_path=CUSTOM_CHROOT_PATH)
+    # These two patches are only necessary or have any affect on the test when
+    # the test is run inside of a symlinked chroot. The _ReadChrootLink patch
+    # ensures it runs as if it is not in a symlinked chroot. The realpath
+    # patch is necessary to make it actually behave as if that's the case.
+    # In both instances the effective return value are as if it was not in a
+    # symlinked chroot.
+    # TODO(saklein) Rewrite these tests so this isn't necessary.
+    self.PatchObject(resolver, '_ReadChrootLink', return_value=None)
+    self.PatchObject(os.path, 'realpath', side_effect=lambda x: x)
+
+    # Case: source root path.
+    self.assertEqual(
+        os.path.join(constants.SOURCE_ROOT, 'some/path'),
+        resolver.FromChroot(os.path.join(constants.CHROOT_SOURCE_ROOT,
+                                         'some/path')))
+
+    # Case: cyclic source/chroot sub-path
+    self.assertEqual(
+        os.path.join(constants.SOURCE_ROOT,
+                     constants.DEFAULT_CHROOT_DIR,
+                     constants.CHROOT_SOURCE_ROOT.lstrip(os.path.sep),
+                     constants.DEFAULT_CHROOT_DIR,
+                     constants.CHROOT_SOURCE_ROOT.lstrip(os.path.sep),
+                     'some/path'),
+        resolver.FromChroot(os.path.join(
+            constants.CHROOT_SOURCE_ROOT,
+            constants.DEFAULT_CHROOT_DIR,
+            constants.CHROOT_SOURCE_ROOT.lstrip(os.path.sep),
+            constants.DEFAULT_CHROOT_DIR,
+            constants.CHROOT_SOURCE_ROOT.lstrip(os.path.sep),
+            'some/path')))
+
+    # Case: path inside the cache directory.
+    self.assertEqual(
+        os.path.join(path_util.GetCacheDir(), 'some/path'),
+        resolver.FromChroot(os.path.join(constants.CHROOT_CACHE_ROOT,
+                                         'some/path')))
+
+    # Case: non-rooted chroot paths.
+    self.assertEqual(
+        os.path.join(self.chroot_path, 'some/path'),
+        resolver.FromChroot('/some/path'))
+
+  @mock.patch('chromite.lib.cros_build_lib.IsInsideChroot', return_value=False)
   def testSymlinkedChroot(self, _):
     self.SetChrootPath(constants.SOURCE_ROOT)
     resolver = path_util.ChrootPathResolver()
diff --git a/lib/paygen/paygen_build_lib.py b/lib/paygen/paygen_build_lib.py
index 68d8bf5..070ed09 100644
--- a/lib/paygen/paygen_build_lib.py
+++ b/lib/paygen/paygen_build_lib.py
@@ -1267,9 +1267,8 @@
       suite_name=suite_name,
       build=build)
 
-  # Double timeout for crbug.com/930256. Will change back once paygen
-  # suites been migrated to skylab.
-  timeout_mins = 2 * config_lib.HWTestConfig.SHARED_HW_TEST_TIMEOUT // 60
+  # 4x timeout for b/209034161.
+  timeout_mins = 4 * config_lib.HWTestConfig.SHARED_HW_TEST_TIMEOUT // 60
   tags = ['build:%s' % build,
           'suite:%s' % suite_name,
           'user:PaygenTestStage']
diff --git a/lib/paygen/paygen_payload_lib.py b/lib/paygen/paygen_payload_lib.py
index d219f9c..ca8ba95 100644
--- a/lib/paygen/paygen_payload_lib.py
+++ b/lib/paygen/paygen_payload_lib.py
@@ -61,6 +61,18 @@
   """Raised when the generated payload fails to verify."""
 
 
+class PayloadGenerationSkippedException(BaseException):
+  """Base class for reasons that payload generation might be skipped.
+
+  Inherits from BaseException instead of Exception since it is not technically
+  an error.
+  """
+
+
+class NoMiniOSPartitionException(PayloadGenerationSkippedException):
+  """Raised when generating a miniOS payload for an img with no miniOS part."""
+
+
 class PaygenPayload(object):
   """Class to manage the process of generating and signing a payload."""
 
@@ -98,7 +110,7 @@
       work_dir: A working directory inside the chroot to put temporary files.
           This can NOT be shared among different runs of PaygenPayload otherwise
           there would be file collisions. Among the things that may go into this
-          direcotry are intermediate image files, extracted partitions,
+          directory are intermediate image files, extracted partitions,
           different logs and metadata files, payload and metadata hashes along
           with their signatures, the payload itself, postinstall config file,
           intermediate files that is generated by the signer, etc.
@@ -306,41 +318,56 @@
                          minor_version)
         return app_id, minor_version
 
-  def _ShouldSkipPayloadGeneration(self):
-    """Returns whether payload generation should be skipped.
+  def _MaybeSkipPayloadGeneration(self):
+    """Raises an exception if paygen should be skipped for some reason.
 
-    Due to target or source images not meeting the requirements for payload
-    generation.
-
-    Returns:
-      bool: True if payload generation should be skipped.
+    Raises:
+      NoMiniOSPartitionException: If a miniOS payload is requested when either
+          the source or target image has no miniOS payload.
     """
-    if not self.payload.minios:
-      return False
-
-    # For miniOS extraction payloads:
-    # Check to see if both target and source images have miniOS partitions.
-    try:
-      tgt_disk = cgpt.Disk.FromImage(self.tgt_image_file)
+    if self.payload.minios:
       try:
-        tgt_disk.GetPartitionByTypeGuid(cgpt.MINIOS_TYPE_GUID)
-      except KeyError:
-        logging.info('Target missing miniOS partition')
-        return True
-
-      if self.payload.src_image:
-        src_disk = cgpt.Disk.FromImage(self.src_image_file)
-        try:
-          src_disk.GetPartitionByTypeGuid(cgpt.MINIOS_TYPE_GUID)
-        except KeyError:
-          logging.info('Source missing miniOS partition')
-          return True
-    except Error:
-      logging.warning('Exception during miniOS payload generation skip check.')
+        if self._EitherImageIsMissingMiniOSPayload():
+          raise NoMiniOSPartitionException
+      except Error as e:
+        logging.warning(
+            'Caught exception checking whether images have miniOS parts: %s', e)
       return True
-
     return False
 
+  def _EitherImageIsMissingMiniOSPayload(self):
+    """Determines whether the source or target image has no miniOS parts.
+
+    If this is a full payload, then there is no src image. In that case, only
+    the tgt image will be evaluated.
+
+    Returns:
+      bool: True if either the target image or the source image (if it exists)
+          has no miniOS partition.
+    """
+    if not self._ImageHasMiniOSPartition(self.tgt_image_file):
+      logging.info('Target missing miniOS partition')
+      return True
+    if self.payload.src_image \
+        and not self._ImageHasMiniOSPartition(self.src_image_file):
+      return True
+    return False
+
+  def _ImageHasMiniOSPartition(self, image_file):
+    """Returns whether the given image has a miniOS partition.
+
+    Args:
+      image_file: Local path to the image file.
+
+    Returns:
+      bool: True if the image has a miniOS partition.
+    """
+    disk = cgpt.Disk.FromImage(image_file)
+    try:
+      disk.GetPartitionByTypeGuid(cgpt.MINIOS_TYPE_GUID)
+    except KeyError:
+      return False
+    return True
 
   def _PreparePartitions(self):
     """Prepares parameters related to partitions of the given image.
@@ -907,8 +934,8 @@
   def _Create(self):
     """Create a given payload, if it doesn't already exist.
 
-    Returns:
-      A bool, True if the payload was created. False doesn't indicate failure.
+    Raises:
+      PayloadGenerationSkippedException: If paygen was skipped for any reason.
     """
 
     logging.info('Generating %s payload %s',
@@ -949,9 +976,7 @@
         self._PrepareImage(self.payload.src_image, self.src_image_file)
 
       # Check if payload generation should proceed.
-      if self._ShouldSkipPayloadGeneration():
-        logging.info('Skipping payload generation.')
-        return False
+      self._MaybeSkipPayloadGeneration()
 
       # Setup parameters about the payload like whether it is a DLC or not. Or
       # parameters like the APPID, etc.
@@ -959,6 +984,9 @@
 
       # Generate the unsigned payload.
       self._GenerateUnsignedPayload()
+    except PayloadGenerationSkippedException:
+      logging.info('Skipping payload generation.')
+      raise
     finally:
       _mem_semaphore.release()
       # Time the actual paygen operation ended.
@@ -971,8 +999,6 @@
     # Store hash and signatures json.
     self._StorePayloadJson(metadata_signatures)
 
-    return True
-
   def _VerifyPayload(self):
     """Checks the integrity of the generated payload.
 
@@ -1035,17 +1061,26 @@
 
     Returns:
       A string uri to payload, if uploaded, otherwise None.
+
+    Raises:
+      PayloadGenerationSkippedException: If paygen was skipped for any reason.
     """
     ret_uri = None
     logging.info('* Starting payload generation')
     start_time = datetime.datetime.now()
 
-    if self._Create():
+    try:
+      self._Create()
       if self._verify:
         self._VerifyPayload()
       if self._upload:
         self._UploadResults()
         ret_uri = self.payload.uri
+    except PayloadGenerationSkippedException:
+      if self._verify:
+        print('Not verifying payload, because paygen was skipped.')
+      if self._upload:
+        print('Not uploading payload, because paygen was skipped.')
 
     end_time = datetime.datetime.now()
     logging.info('* Total elapsed payload generation in %s',
@@ -1066,7 +1101,10 @@
   # We need to create a temp directory inside the chroot so be able to access
   # from both inside and outside the chroot.
   with chroot_util.TempDirInChroot() as work_dir:
-    PaygenPayload(payload, work_dir, sign=sign, verify=verify).Run()
+    try:
+      PaygenPayload(payload, work_dir, sign=sign, verify=verify).Run()
+    except PayloadGenerationSkippedException:
+      pass
 
 
 def GenerateUpdatePayload(tgt_image, payload, src_image=None, work_dir=None,
@@ -1097,7 +1135,10 @@
     work_dir = work_dir if work_dir is not None else temp_dir
     paygen = PaygenPayload(payload, work_dir, sign=private_key is not None,
                            verify=check, private_key=private_key)
-    paygen.Run()
+    try:
+      paygen.Run()
+    except PayloadGenerationSkippedException:
+      logging.info('No payload generated.')
 
 
 def GenerateUpdatePayloadPropertiesFile(payload, output=None):
diff --git a/lib/paygen/paygen_payload_lib_unittest.py b/lib/paygen/paygen_payload_lib_unittest.py
index 978ad06..ebf6546 100644
--- a/lib/paygen/paygen_payload_lib_unittest.py
+++ b/lib/paygen/paygen_payload_lib_unittest.py
@@ -455,8 +455,8 @@
                                 work_dir=self.tempdir, minios=True)
     # Mock out needed functions.
     self.PatchObject(partition_lib, 'LookupImageType',
-                    return_value=partition_lib.CROS_IMAGE)
-    params_mock = self.PatchObject(gen,'_GetPlatformImageParams',
+                     return_value=partition_lib.CROS_IMAGE)
+    params_mock = self.PatchObject(gen, '_GetPlatformImageParams',
                                    return_value=('foo-appid_minios', None))
     minios_ext_mock = self.PatchObject(partition_lib, 'ExtractMiniOS')
     tgt_image_file = gen.tgt_image_file
@@ -480,7 +480,7 @@
     This test is for delta payloads only.
     """
     gen = self._GetStdGenerator(payload=self.delta_payload,
-                              work_dir=self.tempdir, minios=True)
+                                work_dir=self.tempdir, minios=True)
     # Mock out needed functions.
     self.PatchObject(partition_lib, 'LookupImageType',
                      return_value=partition_lib.CROS_IMAGE)
@@ -584,7 +584,7 @@
                      return_value=('foo-appid_minios', '6'))
 
     # Run the test.
-    _,gen._minor_version = gen._GetPlatformImageParams(gen.tgt_image_file)
+    _, gen._minor_version = gen._GetPlatformImageParams(gen.tgt_image_file)
     gen._GenerateUnsignedPayload()
 
     # Check the expected function calls.
@@ -834,11 +834,12 @@
     prep_image_mock = self.PatchObject(paygen_payload_lib.PaygenPayload,
                                        '_PrepareImage')
     check_minios_mock = self.PatchObject(paygen_payload_lib.PaygenPayload,
-                                         '_ShouldSkipPayloadGeneration',
+                                         '_EitherImageIsMissingMiniOSPayload',
                                          return_value=True)
 
     # Run the test.
-    self.assertFalse(gen._Create())
+    with self.assertRaises(paygen_payload_lib.NoMiniOSPartitionException):
+      gen._Create()
 
     # Check expected calls.
     self.assertEqual(prep_image_mock.call_args_list, [
@@ -855,7 +856,7 @@
     prep_image_mock = self.PatchObject(paygen_payload_lib.PaygenPayload,
                                        '_PrepareImage')
     check_minios_mock = self.PatchObject(paygen_payload_lib.PaygenPayload,
-                                         '_ShouldSkipPayloadGeneration',
+                                         '_EitherImageIsMissingMiniOSPayload',
                                          return_value=False)
     prep_part_mock = self.PatchObject(paygen_payload_lib.PaygenPayload,
                                       '_PreparePartitions')
@@ -868,7 +869,7 @@
                                   '_StorePayloadJson')
 
     # Run the test.
-    self.assertTrue(gen._Create())
+    gen._Create()
 
     # Check expected calls.
     self.assertEqual(prep_image_mock.call_args_list, [
diff --git a/lib/paygen/signer_payloads_client.py b/lib/paygen/signer_payloads_client.py
index 71be2f3..085fbd0 100644
--- a/lib/paygen/signer_payloads_client.py
+++ b/lib/paygen/signer_payloads_client.py
@@ -345,8 +345,9 @@
       # [sig_uri, ...]
       all_signature_uris = []
 
-      # { hash : [sig_uri, ...], ... }
-      hash_signature_uris = dict([(h, []) for h in hashes])
+      # hash[0]           hash[1]
+      # [ [sig_uri, ...], [sig_uri, ... ] ... ]
+      hash_signature_uris = [[] for _ in range(len(hashes))]
 
       # Upload one signing instruction file and signing request for
       # each keyset.
@@ -366,8 +367,8 @@
         uris = self._CreateSignatureURIs(hash_names, keyset)
 
         all_signature_uris += uris
-        for h, sig_uri in zip(hashes, uris):
-          hash_signature_uris[h].append(sig_uri)
+        for hash_signature_uri, sig_uri in zip(hash_signature_uris, uris):
+          hash_signature_uri.append(sig_uri)
 
       # Wait for the signer to finish all keysets.
       if not self._WaitForSignatures(all_signature_uris):
@@ -375,7 +376,9 @@
         return None
 
       # Download the results.
-      return [self._DownloadSignatures(hash_signature_uris[h]) for h in hashes]
+      return [self._DownloadSignatures(hash_signature_uri)
+              for hash_signature_uri
+              in hash_signature_uris]
 
     finally:
       # Clean up the signature related files from this run.
diff --git a/lib/paygen/signer_payloads_client_unittest.py b/lib/paygen/signer_payloads_client_unittest.py
index 83d0533..34bcc2e 100644
--- a/lib/paygen/signer_payloads_client_unittest.py
+++ b/lib/paygen/signer_payloads_client_unittest.py
@@ -383,7 +383,7 @@
     clean_uri = ('gs://chromeos-releases/test-channel/%s/crostools-client/**' %
                  (cros_build_lib.GetRandomString(),))
 
-    # Cleanup before we start
+    # Cleanup before we start.
     ctx.Remove(clean_uri, ignore_missing=True)
 
     try:
@@ -434,6 +434,54 @@
       # Cleanup when we are over.
       ctx.Remove(clean_uri, ignore_missing=True)
 
+  @cros_test_lib.pytestmark_network_test
+  def testGetHashSignaturesDuplicates(self):
+    """Integration test with real signer with duplicate test hashes."""
+    ctx = gs.GSContext()
+
+    clean_uri = ('gs://chromeos-releases/test-channel/%s/crostools-client/**' %
+                 (cros_build_lib.GetRandomString(),))
+
+    # Cleanup before we start.
+    ctx.Remove(clean_uri, ignore_missing=True)
+
+    try:
+      hashes = [b'0' * 32,
+                b'0' * 32]
+
+      keysets = ['update_signer']
+
+      expected_sigs_hex = (
+          ('ba4c7a86b786c609bf6e4c5fb9c47525608678caa532bea8acc457aa6dd32b43'
+           '5f094b331182f2e167682916990c40ff7b6b0128de3fa45ad0fd98041ec36d6f'
+           '63b867bcf219804200616590a41a727c2685b48340efb4b480f1ef448fc7bc3f'
+           'b1c4b53209e950ecc721b07a52a41d9c025fd25602340c93d5295211308caa29'
+           'a03ed18516cf61411c508097d5b47620d643ed357b05213b2b9fa3a3f938d6c4'
+           'f52b85c3f9774edc376902458344d1c1cd72bc932f033c076c76fee2400716fe'
+           '652306871ba923021ce245e0c778ad9e0e50e87a169b2aea338c4dc8b5c0c716'
+           'aabfb6133482e8438b084a09503db27ca546e910f8938f7805a8a76a3b0d0241',),
+
+          ('ba4c7a86b786c609bf6e4c5fb9c47525608678caa532bea8acc457aa6dd32b43'
+           '5f094b331182f2e167682916990c40ff7b6b0128de3fa45ad0fd98041ec36d6f'
+           '63b867bcf219804200616590a41a727c2685b48340efb4b480f1ef448fc7bc3f'
+           'b1c4b53209e950ecc721b07a52a41d9c025fd25602340c93d5295211308caa29'
+           'a03ed18516cf61411c508097d5b47620d643ed357b05213b2b9fa3a3f938d6c4'
+           'f52b85c3f9774edc376902458344d1c1cd72bc932f033c076c76fee2400716fe'
+           '652306871ba923021ce245e0c778ad9e0e50e87a169b2aea338c4dc8b5c0c716'
+           'aabfb6133482e8438b084a09503db27ca546e910f8938f7805a8a76a3b0d0241',))
+
+      expected_sigs = [[base64.b16decode(x[0], True)]
+                       for x in expected_sigs_hex]
+
+      all_signatures = self.client.GetHashSignatures(hashes, keysets)
+
+      self.assertEqual(all_signatures, expected_sigs)
+      self.assertRaises(gs.GSNoSuchKey, ctx.List, clean_uri)
+
+    finally:
+      # Cleanup when we are over.
+      ctx.Remove(clean_uri, ignore_missing=True)
+
 
 class UnofficialPayloadSignerTest(cros_test_lib.TestCase):
   """Test suit for testing unofficial local payload signer."""
diff --git a/lib/perf_uploader.py b/lib/perf_uploader.py
index bd4f7d4..436df4a 100644
--- a/lib/perf_uploader.py
+++ b/lib/perf_uploader.py
@@ -221,7 +221,7 @@
 
 PresentationInfo = collections.namedtuple(
     'PresentationInfo',
-    'master_name test_name')
+    'main_name test_name')
 
 
 def _GetPresentationInfo(test_name):
@@ -240,7 +240,7 @@
       try:
         return PresentationInfo(**info)
       except:
-        raise PerfUploadingError('No master found for %s' % test_name)
+        raise PerfUploadingError('No main found for %s' % test_name)
 
   raise PerfUploadingError('No presentation config found for %s' % test_name)
 
@@ -254,7 +254,7 @@
   specially-formatted JSON string.  In particular, the JSON object must be a
   dictionary with key "data", and value being a list of dictionaries where
   each dictionary contains all the information associated with a single
-  measured perf value: master name, bot name, test name, perf value, units,
+  measured perf value: main name, bot name, test name, perf value, units,
   and build version numbers.
 
   See also google3/googleclient/chrome/speed/dashboard/add_point.py for the
@@ -305,7 +305,7 @@
       supp_cols['r_chrome_version'] = chrome_version
 
     new_dash_entry = {
-        'master': presentation_info.master_name,
+        'main': presentation_info.main_name,
         'bot': platform_prefix + platform_name,
         'test': test_path,
         'value': data['value'],
@@ -433,7 +433,7 @@
 
 def UploadPerfValues(perf_values, platform_name, test_name, revision=None,
                      cros_version=None, chrome_version=None,
-                     dashboard=DASHBOARD_URL, master_name=None,
+                     dashboard=DASHBOARD_URL, main_name=None,
                      test_prefix=None, platform_prefix=None, dry_run=False):
   """Uploads any perf data associated with a test to the perf dashboard.
 
@@ -451,7 +451,7 @@
     cros_version: A string identifying Chrome OS version e.g. '6052.0.0'.
     chrome_version: A string identifying Chrome version e.g. '38.0.2091.2'.
     dashboard: The dashboard to upload data to.
-    master_name: The "master" field to use; by default it is looked up in the
+    main_name: The "main" field to use; by default it is looked up in the
       perf_dashboard_config.json database.
     test_prefix: Arbitrary string to automatically prefix to the test name.
       If None, then 'cbuildbot.' is used to guarantee namespacing.
@@ -477,10 +477,10 @@
     cros_version = chrome_version[:chrome_version.find('.') + 1] + cros_version
     revision = _ComputeRevisionFromVersions(chrome_version, cros_version)
   try:
-    if master_name is None:
+    if main_name is None:
       presentation_info = _GetPresentationInfo(test_name)
     else:
-      presentation_info = PresentationInfo(master_name, test_name)
+      presentation_info = PresentationInfo(main_name, test_name)
     formatted_data = _FormatForUpload(perf_data, platform_name,
                                       presentation_info,
                                       revision=revision,
diff --git a/lib/perf_uploader_unittest.py b/lib/perf_uploader_unittest.py
index 0c0f9db..5f6a1d8 100644
--- a/lib/perf_uploader_unittest.py
+++ b/lib/perf_uploader_unittest.py
@@ -20,7 +20,7 @@
 
   def setUp(self):
     presentation_info = perf_uploader.PresentationInfo(
-        master_name='ChromeOSPerf',
+        main_name='ChromeOSPerf',
         test_name='TestName',
     )
     self.PatchObject(perf_uploader, '_GetPresentationInfo',
diff --git a/lib/portage_util.py b/lib/portage_util.py
index 0569461..89a12f3 100644
--- a/lib/portage_util.py
+++ b/lib/portage_util.py
@@ -14,7 +14,8 @@
 import os
 import re
 import shutil
-from typing import Dict, List, Optional
+from pathlib import Path
+from typing import Dict, Iterator, List, Optional, Union
 
 from chromite.lib import build_target_lib
 from chromite.lib import constants
@@ -26,12 +27,10 @@
 from chromite.lib.parser import package_info
 from chromite.utils import key_value_store
 
-
 # The parsed output of running `ebuild <ebuild path> info`.
 RepositoryInfoTuple = collections.namedtuple('RepositoryInfoTuple',
                                              ('srcdir', 'project'))
 
-
 _PRIVATE_PREFIX = '%(buildroot)s/src/private-overlays'
 
 # This regex matches a category name.
@@ -51,9 +50,8 @@
 
 # A structure to hold computed values of CROS_WORKON_*.
 CrosWorkonVars = collections.namedtuple(
-    'CrosWorkonVars',
-    ('localname', 'project', 'srcpath', 'subdir', 'always_live', 'commit',
-     'rev_subdirs', 'subtrees'))
+    'CrosWorkonVars', ('localname', 'project', 'srcpath', 'subdir',
+                       'always_live', 'commit', 'rev_subdirs', 'subtrees'))
 
 # EBuild source information computed from CrosWorkonVars.
 SourceInfo = collections.namedtuple(
@@ -152,6 +150,7 @@
   # Build up the list of repos we need.
   ret = []
   seen = set()
+
   def _AddRepo(repo, optional=False):
     """Recursively add |repo|'s masters from |overlays| to |ret|.
 
@@ -244,7 +243,9 @@
   return list(overlays)
 
 
-def FindOverlayFile(filename, overlay_type=constants.BOTH_OVERLAYS, board=None,
+def FindOverlayFile(filename,
+                    overlay_type=constants.BOTH_OVERLAYS,
+                    board=None,
                     buildroot=constants.SOURCE_ROOT):
   """Attempt to find a file in the overlay directories.
 
@@ -284,7 +285,9 @@
   return PortageqEnvvar('PORTDIR_OVERLAY', board=os.path.basename(sysroot))
 
 
-def ReadOverlayFile(filename, overlay_type=constants.BOTH_OVERLAYS, board=None,
+def ReadOverlayFile(filename,
+                    overlay_type=constants.BOTH_OVERLAYS,
+                    board=None,
                     buildroot=constants.SOURCE_ROOT):
   """Attempt to open a file in the overlay directories.
 
@@ -344,8 +347,9 @@
 
 
 # Container for Classify return values.
-EBuildClassifyAttributes = collections.namedtuple('EBuildClassifyAttributes', (
-    'is_workon', 'is_stable', 'is_manually_uprevved', 'has_test'))
+EBuildClassifyAttributes = collections.namedtuple(
+    'EBuildClassifyAttributes',
+    ('is_workon', 'is_stable', 'is_manually_uprevved', 'has_test'))
 
 
 class EBuild(object):
@@ -364,10 +368,10 @@
   # These eclass files imply that src_test is defined for an ebuild.
   _ECLASS_IMPLIES_TEST = {
       'cros-common.mk',
-      'cros-ec',      # defines src_test
+      'cros-ec',  # defines src_test
       'cros-firmware',
-      'cros-go',      # defines src_test
-      'cros-rust',    # defines src_test
+      'cros-go',  # defines src_test
+      'cros-rust',  # defines src_test
       'tast-bundle',  # inherits cros-go
   }
 
@@ -420,8 +424,11 @@
     osutils.WriteFile(ebuild_path, '\n'.join(new_lines) + '\n')
 
   @classmethod
-  def MarkAsStable(cls, unstable_ebuild_path, new_stable_ebuild_path,
-                   variables, make_stable=True):
+  def MarkAsStable(cls,
+                   unstable_ebuild_path,
+                   new_stable_ebuild_path,
+                   variables,
+                   make_stable=True):
     """Static function that creates a revved stable ebuild.
 
     This function assumes you have already figured out the name of the new
@@ -477,10 +484,10 @@
 
     self._ebuild_path_no_version = os.path.join(
         os.path.dirname(path), self.pkgname)
-    self.ebuild_path_no_revision = '%s-%s' % (
-        self._ebuild_path_no_version, self.version_no_rev)
-    self._unstable_ebuild_path = '%s%s' % (
-        self._ebuild_path_no_version, WORKON_EBUILD_SUFFIX)
+    self.ebuild_path_no_revision = '%s-%s' % (self._ebuild_path_no_version,
+                                              self.version_no_rev)
+    self._unstable_ebuild_path = '%s%s' % (self._ebuild_path_no_version,
+                                           WORKON_EBUILD_SUFFIX)
     self.ebuild_path = path
 
     self.is_workon = False
@@ -491,8 +498,8 @@
 
     # Grab the latest project settings.
     try:
-      new_vars = EBuild.GetCrosWorkonVars(
-          self._unstable_ebuild_path, self.pkgname)
+      new_vars = EBuild.GetCrosWorkonVars(self._unstable_ebuild_path,
+                                          self.pkgname)
     except EbuildFormatIncorrectError:
       new_vars = None
 
@@ -532,8 +539,8 @@
         try:
           line = line.decode('utf-8')
         except UnicodeDecodeError:
-          logging.exception('%s: line %i: invalid UTF-8: %s',
-                            ebuild_path, i, line)
+          logging.exception('%s: line %i: invalid UTF-8: %s', ebuild_path, i,
+                            line)
           raise
 
         if line.startswith('inherit '):
@@ -557,17 +564,16 @@
           has_test = True
         elif line.startswith('RESTRICT=') and 'test' in line:
           restrict_tests = True
-    return EBuildClassifyAttributes(
-        is_workon, is_stable, is_manually_uprevved,
-        has_test and not restrict_tests)
+    return EBuildClassifyAttributes(is_workon, is_stable, is_manually_uprevved,
+                                    has_test and not restrict_tests)
 
   def _ReadEBuild(self, path):
     """Determine the settings of is_workon, is_stable and is_manually_uprevved
 
     These are determined using the static Classify function.
     """
-    (self.is_workon, self.is_stable,
-     self.is_manually_uprevved, self.has_test) = EBuild.Classify(path)
+    (self.is_workon, self.is_stable, self.is_manually_uprevved,
+     self.has_test) = EBuild.Classify(path)
 
   @staticmethod
   def _GetAutotestTestsFromSettings(settings):
@@ -611,8 +617,8 @@
       return results
 
     # TODO(pmalani): Can we get this from get_test_list in autotest.eclass ?
-    settings = osutils.SourceEnvironment(ebuild_path, test_vars, env=None,
-                                         multiline=True)
+    settings = osutils.SourceEnvironment(
+        ebuild_path, test_vars, env=None, multiline=True)
     if 'IUSE_TESTS' not in settings:
       return results
 
@@ -703,7 +709,8 @@
     commit = settings.get('CROS_WORKON_COMMIT')
     subtrees = [
         tuple(subtree.split() or [''])
-        for subtree in settings.get('CROS_WORKON_SUBTREE', '').split(',')]
+        for subtree in settings.get('CROS_WORKON_SUBTREE', '').split(',')
+    ]
     if (len(projects) > 1 or len(srcpaths) > 1) and rev_subdirs:
       raise EbuildFormatIncorrectError(
           ebuild_path,
@@ -747,24 +754,21 @@
     # Each project specification has to have the same amount of items.
     if num_projects != len(localnames):
       raise EbuildFormatIncorrectError(
-          ebuild_path,
-          "Number of _PROJECT and _LOCALNAME items don't match.")
+          ebuild_path, "Number of _PROJECT and _LOCALNAME items don't match.")
 
     # If both SRCPATH and PROJECT are defined, they must have the same number
     # of items.
     if len(srcpaths) > num_projects:
       if num_projects > 0:
         raise EbuildFormatIncorrectError(
-            ebuild_path,
-            '_PROJECT has fewer items than _SRCPATH.')
+            ebuild_path, '_PROJECT has fewer items than _SRCPATH.')
       num_projects = len(srcpaths)
       projects = [''] * num_projects
       localnames = [''] * num_projects
     elif len(srcpaths) < num_projects:
       if srcpaths:
         raise EbuildFormatIncorrectError(
-            ebuild_path,
-            '_SRCPATH has fewer items than _PROJECT.')
+            ebuild_path, '_SRCPATH has fewer items than _PROJECT.')
       srcpaths = [''] * num_projects
 
     if subdirs:
@@ -778,14 +782,14 @@
 
     # We better have at least one PROJECT or SRCPATH value at this point.
     if num_projects == 0:
-      raise EbuildFormatIncorrectError(
-          ebuild_path, 'No _PROJECT or _SRCPATH value found.')
+      raise EbuildFormatIncorrectError(ebuild_path,
+                                       'No _PROJECT or _SRCPATH value found.')
 
     # Subtree must be either 1 or len(project).
     if num_projects != len(subtrees):
       if len(subtrees) > 1:
-        raise EbuildFormatIncorrectError(
-            ebuild_path, 'Incorrect number of _SUBTREE items.')
+        raise EbuildFormatIncorrectError(ebuild_path,
+                                         'Incorrect number of _SUBTREE items.')
       # Multiply by num_projects. Note that subtrees is a list of tuples, and
       # there should be at least one element.
       subtrees *= num_projects
@@ -831,8 +835,9 @@
 
     srcbase = ''
     if any(srcpaths):
-      base_dir = os.path.dirname(os.path.dirname(os.path.dirname(
-          os.path.dirname(self._unstable_ebuild_path))))
+      base_dir = os.path.dirname(
+          os.path.dirname(
+              os.path.dirname(os.path.dirname(self._unstable_ebuild_path))))
       srcbase = os.path.join(base_dir, 'src')
       if not os.path.isdir(srcbase):
         raise Error('_SRCPATH used but source path not found.')
@@ -851,8 +856,9 @@
 
     subdir_paths = []
     subtree_paths = []
-    for local, project, srcpath, subdir, subtree in zip(
-        localnames, projects, srcpaths, subdirs, subtrees):
+    for local, project, srcpath, subdir, subtree in zip(localnames, projects,
+                                                        srcpaths, subdirs,
+                                                        subtrees):
 
       if srcpath:
         subdir_path = os.path.join(srcbase, srcpath)
@@ -864,8 +870,8 @@
       else:
         subdir_path = os.path.realpath(os.path.join(srcroot, dir_, local))
         if dir_ == '' and not os.path.isdir(subdir_path):
-          subdir_path = os.path.realpath(os.path.join(srcroot, 'platform',
-                                                      local))
+          subdir_path = os.path.realpath(
+              os.path.join(srcroot, 'platform', local))
 
         if self.subdir_support and subdir:
           subdir_path = os.path.join(subdir_path, subdir)
@@ -874,9 +880,8 @@
         real_project = manifest.FindCheckoutFromPath(subdir_path)['name']
         if project != real_project:
           raise Error('Project name mismatch for %s '
-                      '(found %s, expected %s)' % (subdir_path,
-                                                   real_project,
-                                                   project))
+                      '(found %s, expected %s)' %
+                      (subdir_path, real_project, project))
 
       if subdir_path == ebuild_git_tree_path:
         msg = ('%s: ebuilds may not live in & track the same source '
@@ -888,11 +893,12 @@
           logging.warning('Ignoring error: %s', msg)
       subdir_paths.append(subdir_path)
       subtree_paths.extend(
-          os.path.join(subdir_path, s) if s else subdir_path
-          for s in subtree)
+          os.path.join(subdir_path, s) if s else subdir_path for s in subtree)
 
     return SourceInfo(
-        projects=projects, srcdirs=subdir_paths, subdirs=[],
+        projects=projects,
+        srcdirs=subdir_paths,
+        subdirs=[],
         subtrees=subtree_paths)
 
   def GetCommitId(self, srcdir, ref: str = 'HEAD'):
@@ -948,8 +954,9 @@
       raise Error when chromeos-version.sh script fails to return the raw
         version number.
     """
-    vers_script = os.path.join(os.path.dirname(self._ebuild_path_no_version),
-                               'files', 'chromeos-version.sh')
+    vers_script = os.path.join(
+        os.path.dirname(self._ebuild_path_no_version), 'files',
+        'chromeos-version.sh')
 
     if not os.path.exists(vers_script):
       return default
@@ -965,7 +972,9 @@
     # or nothing in case of error or no available version
     result = cros_build_lib.run(
         ['bash', '-x', vers_script] + srcdirs,
-        capture_output=True, check=False, encoding='utf-8')
+        capture_output=True,
+        check=False,
+        encoding='utf-8')
 
     output = result.output.strip()
     if result.returncode or not output:
@@ -982,8 +991,8 @@
     except ValueError:
       raise ValueError('%s: PV returned is invalid: %s' % (vers_script, output))
     if main_pv >= int(WORKON_EBUILD_VERSION):
-      raise ValueError('%s: cros-workon packages must have a PV < %s; not %s'
-                       % (vers_script, WORKON_EBUILD_VERSION, output))
+      raise ValueError('%s: cros-workon packages must have a PV < %s; not %s' %
+                       (vers_script, WORKON_EBUILD_VERSION, output))
 
     # Sanity check: We should be able to parse a CPV string with the produced
     # version number.
@@ -1047,14 +1056,12 @@
       logging.critical('%s: uprev failed: %s', self.ebuild_path, e)
       raise
 
-    old_version = '%s-r%d' % (
-        stable_version_no_rev, self.current_revision)
-    old_stable_ebuild_path = '%s-%s.ebuild' % (
-        self._ebuild_path_no_version, old_version)
-    new_version = '%s-r%d' % (
-        stable_version_no_rev, self.current_revision + 1)
-    new_stable_ebuild_path = '%s-%s.ebuild' % (
-        self._ebuild_path_no_version, new_version)
+    old_version = '%s-r%d' % (stable_version_no_rev, self.current_revision)
+    old_stable_ebuild_path = '%s-%s.ebuild' % (self._ebuild_path_no_version,
+                                               old_version)
+    new_version = '%s-r%d' % (stable_version_no_rev, self.current_revision + 1)
+    new_stable_ebuild_path = '%s-%s.ebuild' % (self._ebuild_path_no_version,
+                                               new_version)
 
     info = self.GetSourceInfo(
         srcroot, manifest, reject_self_repo=reject_self_repo)
@@ -1068,8 +1075,9 @@
     tree_ids = [tree_id for tree_id in tree_ids if tree_id]
     if not tree_ids:
       raise InvalidUprevSourceError('No tree_ids found for %s' % subtrees)
-    variables = dict(CROS_WORKON_COMMIT=self.FormatBashArray(commit_ids),
-                     CROS_WORKON_TREE=self.FormatBashArray(tree_ids))
+    variables = dict(
+        CROS_WORKON_COMMIT=self.FormatBashArray(commit_ids),
+        CROS_WORKON_TREE=self.FormatBashArray(tree_ids))
 
     # We use |self._unstable_ebuild_path| because that will contain the newest
     # changes to the ebuild (and potentially changes to test subdirs
@@ -1092,14 +1100,14 @@
       if not os.path.exists(old_stable_ebuild_path):
         return True
 
-      old_stable_commit = self._RunGit(self.overlay,
-                                       ['log', '--pretty=%H', '-n1', '--',
-                                        old_stable_ebuild_path]).rstrip()
-      output = self._RunGit(self.overlay,
-                            ['log', '%s..HEAD' % old_stable_commit, '--',
-                             self._unstable_ebuild_path,
-                             os.path.join(os.path.dirname(self.ebuild_path),
-                                          'files')])
+      old_stable_commit = self._RunGit(
+          self.overlay,
+          ['log', '--pretty=%H', '-n1', '--', old_stable_ebuild_path]).rstrip()
+      output = self._RunGit(self.overlay, [
+          'log',
+          '%s..HEAD' % old_stable_commit, '--', self._unstable_ebuild_path,
+          os.path.join(os.path.dirname(self.ebuild_path), 'files')
+      ])
       return bool(output)
 
     unstable_ebuild_or_files_changed = _CheckForChanges()
@@ -1107,16 +1115,17 @@
     # If there has been any change in the tests list, choose to uprev.
     if (not test_dirs_changed and not unstable_ebuild_or_files_changed and
         not self._ShouldRevEBuild(commit_ids, srcdirs, subdirs_to_rev)):
-      logging.info('Skipping uprev of ebuild %s, none of the rev_subdirs have '
-                   'been modified, no files/, nor has the -9999 ebuild.',
-                   self.pkgname)
+      logging.info(
+          'Skipping uprev of ebuild %s, none of the rev_subdirs have '
+          'been modified, no files/, nor has the -9999 ebuild.', self.pkgname)
       return
 
     logging.info('Determining whether to create new ebuild %s',
                  new_stable_ebuild_path)
 
-    assert os.path.exists(self._unstable_ebuild_path), (
-        'Missing unstable ebuild: %s' % self._unstable_ebuild_path)
+    assert os.path.exists(
+        self._unstable_ebuild_path), ('Missing unstable ebuild: %s' %
+                                      self._unstable_ebuild_path)
 
     self.MarkAsStable(self._unstable_ebuild_path, new_stable_ebuild_path,
                       variables)
@@ -1124,17 +1133,17 @@
     old_ebuild_path = self.ebuild_path
     if (EBuild._AlmostSameEBuilds(old_ebuild_path, new_stable_ebuild_path) and
         not unstable_ebuild_or_files_changed):
-      logging.info('Old and new ebuild %s are exactly identical; '
-                   'skipping uprev', new_stable_ebuild_path)
+      logging.info(
+          'Old and new ebuild %s are exactly identical; '
+          'skipping uprev', new_stable_ebuild_path)
       os.unlink(new_stable_ebuild_path)
       return
     else:
       logging.info('Creating new stable ebuild %s', new_stable_ebuild_path)
-      logging.info('New ebuild commit id: %s',
-                   self.FormatBashArray(commit_ids))
+      logging.info('New ebuild commit id: %s', self.FormatBashArray(commit_ids))
       ebuild_path_to_remove = old_ebuild_path if self.is_stable else None
-      return ('%s-%s' % (self.package, new_version),
-              new_stable_ebuild_path, ebuild_path_to_remove)
+      return ('%s-%s' % (self.package, new_version), new_stable_ebuild_path,
+              ebuild_path_to_remove)
 
   def _ShouldRevEBuild(self, commit_ids, srcdirs, subdirs_to_rev):
     """Determine whether we should attempt to rev |ebuild|.
@@ -1183,12 +1192,14 @@
       return True
 
     if output:
-      logging.info(' Rev: Determined that one+ of the ebuild %s rev_subdirs '
-                   'was touched %s', self.pkgname, list(subdirs_to_rev))
+      logging.info(
+          ' Rev: Determined that one+ of the ebuild %s rev_subdirs '
+          'was touched %s', self.pkgname, list(subdirs_to_rev))
       return True
     else:
-      logging.info('Skip: Determined that none of the ebuild %s rev_subdirs '
-                   'was touched %s', self.pkgname, list(subdirs_to_rev))
+      logging.info(
+          'Skip: Determined that none of the ebuild %s rev_subdirs '
+          'was touched %s', self.pkgname, list(subdirs_to_rev))
       return False
 
   @classmethod
@@ -1206,17 +1217,15 @@
     Even if CROS_WORKON_COMMIT is different, as long as CROS_WORKON_TREE is
     the same, we can guarantee the source tree is identical.
     """
-    return (
-        cls._LoadEBuildForComparison(ebuild_path1) ==
-        cls._LoadEBuildForComparison(ebuild_path2))
+    return (cls._LoadEBuildForComparison(ebuild_path1) ==
+            cls._LoadEBuildForComparison(ebuild_path2))
 
   @classmethod
   def _LoadEBuildForComparison(cls, ebuild_path):
     """Loads an ebuild file dropping CROS_WORKON_COMMIT line."""
     lines = osutils.ReadFile(ebuild_path).splitlines()
     return '\n'.join(
-        line for line in lines
-        if not cls._WORKON_COMMIT_PATTERN.search(line))
+        line for line in lines if not cls._WORKON_COMMIT_PATTERN.search(line))
 
   @classmethod
   def List(cls, package_dir):
@@ -1290,8 +1299,7 @@
       pkg_key = '%s/%s' % (category, pf)
       if pkg_key not in self._ebuilds:
         self._ebuilds[pkg_key] = InstalledPackage(
-            self, os.path.join(self.db_path, category, pf),
-            category, pf)
+            self, os.path.join(self.db_path, category, pf), category, pf)
       packages.append(self._ebuilds[pkg_key])
 
     return packages
@@ -1352,6 +1360,7 @@
                            'format.' % self.pf)
     self.package = split_pv.package
     self.version = split_pv.vr
+    self._pkg_info = None
 
   def _ReadField(self, field_name):
     """Reads the contents of the file in the installed package directory.
@@ -1398,6 +1407,13 @@
   def size(self):
     return self._ReadField('SIZE')
 
+  @property
+  def package_info(self):
+    if not self._pkg_info:
+      self._pkg_info = package_info.parse(f'{self.category}/{self.pf}')
+
+    return self._pkg_info
+
   def ListContents(self):
     """List of files and directories installed by this package.
 
@@ -1465,17 +1481,25 @@
   """
   stable_ebuilds = []
   unstable_ebuilds = []
+  # Track if we found an unstable ebuild that is a manual uprev. This is to
+  # allow adding CROS_WORKON_MANUAL_UPREV to only the unstable ebuild without
+  # causing an error to be thrown here.
+  unstable_manual_uprev = False
   for path in files:
     if not path.endswith('.ebuild') or os.path.islink(path):
       continue
     ebuild = EBuild(path, subdir_support)
-    if not ebuild.is_workon or (ebuild.is_manually_uprevved and
-                                not allow_manual_uprev):
+    if not ebuild.is_workon:
       continue
+    elif ebuild.is_manually_uprevved and not allow_manual_uprev:
+      if not ebuild.is_stable:
+        unstable_manual_uprev = True
+      continue
+
     if ebuild.is_stable:
       if ebuild.version == WORKON_EBUILD_VERSION:
-        raise Error('KEYWORDS in %s ebuild should not be stable %s'
-                    % (WORKON_EBUILD_VERSION, path))
+        raise Error('KEYWORDS in %s ebuild should not be stable %s' %
+                    (WORKON_EBUILD_VERSION, path))
       stable_ebuilds.append(ebuild)
     else:
       unstable_ebuilds.append(ebuild)
@@ -1483,14 +1507,14 @@
   # If both ebuild lists are empty, the passed in file list was for
   # a non-workon package.
   if not unstable_ebuilds:
-    if stable_ebuilds:
+    if stable_ebuilds and not unstable_manual_uprev:
       path = os.path.dirname(stable_ebuilds[0].ebuild_path)
       raise Error('Missing %s ebuild in %s' % (WORKON_EBUILD_VERSION, path))
     return None
 
   path = os.path.dirname(unstable_ebuilds[0].ebuild_path)
-  assert len(unstable_ebuilds) <= 1, (
-      'Found multiple unstable ebuilds in %s' % path)
+  assert len(unstable_ebuilds) <= 1, ('Found multiple unstable ebuilds in %s' %
+                                      path)
 
   if not stable_ebuilds:
     logging.warning('Missing stable ebuild in %s', path)
@@ -1515,7 +1539,10 @@
   return uprev_ebuild
 
 
-def GetOverlayEBuilds(overlay, use_all, packages, allow_manual_uprev=False,
+def GetOverlayEBuilds(overlay,
+                      use_all,
+                      packages,
+                      allow_manual_uprev=False,
                       subdir_support=False):
   """Get ebuilds from the specified overlay.
 
@@ -1557,7 +1584,9 @@
   return ebuilds
 
 
-def _Egencache(repo_name: str, overlay: str, chroot_args: List[str] = None,
+def _Egencache(repo_name: str,
+               overlay: str,
+               chroot_args: List[str] = None,
                log_output: bool = True) -> cros_build_lib.CommandResult:
   """Execute egencache for repo_name inside the chroot.
 
@@ -1570,10 +1599,14 @@
   Returns:
     A cros_build_lib.CommandResult object.
   """
-  return cros_build_lib.run(['egencache', '--update', '--repo', repo_name,
-                             '--jobs', str(multiprocessing.cpu_count())],
-                            cwd=overlay, enter_chroot=True,
-                            chroot_args=chroot_args, log_output=log_output)
+  return cros_build_lib.run([
+      'egencache', '--update', '--repo', repo_name, '--jobs',
+      str(multiprocessing.cpu_count())
+  ],
+                            cwd=overlay,
+                            enter_chroot=True,
+                            chroot_args=chroot_args,
+                            log_output=log_output)
 
 
 def RegenCache(overlay, commit_changes=True, chroot=None):
@@ -1823,14 +1856,18 @@
   Returns:
     A cros_build_lib.CommandResult object.
   """
-  cmd = ['equery']
-  if board:
-    cmd = ['equery-%s' % board]
-
+  cmd = [f'equery-{board}' if board else 'equery']
+  # Simplify output.
+  cmd += ['-Cq']
   cmd += ['list', pkg_str]
+
   return cros_build_lib.run(
-      cmd, cwd=buildroot, enter_chroot=True, capture_output=True,
-      check=False, encoding='utf-8')
+      cmd,
+      cwd=buildroot,
+      enter_chroot=True,
+      capture_output=True,
+      check=False,
+      encoding='utf-8')
 
 
 def FindPackageNameMatches(
@@ -1856,22 +1893,24 @@
   return matches
 
 
-def FindEbuildForBoardPackage(pkg_str, board,
-                              buildroot=constants.SOURCE_ROOT):
+def FindEbuildForBoardPackage(pkg_str: str,
+                              board: str,
+                              buildroot: str = constants.SOURCE_ROOT):
   """Returns a path to an ebuild for a particular board."""
-  equery = 'equery-%s' % board
-  cmd = [equery, 'which', pkg_str]
+  cmd = [f'equery-{board}', 'which', pkg_str]
   return cros_build_lib.run(
-      cmd, cwd=buildroot, enter_chroot=True,
-      capture_output=True, encoding='utf-8').stdout.strip()
+      cmd,
+      cwd=buildroot,
+      enter_chroot=True,
+      capture_output=True,
+      encoding='utf-8').stdout.strip()
 
 
-def _EqueryWhich(
-    packages_list: List[str],
-    sysroot: str,
-    include_masked: bool = False,
-    extra_env: Optional[Dict[str, str]] = None,
-    check: bool = False) -> cros_build_lib.CommandResult:
+def _EqueryWhich(packages_list: List[str],
+                 sysroot: str,
+                 include_masked: bool = False,
+                 extra_env: Optional[Dict[str, str]] = None,
+                 check: bool = False) -> cros_build_lib.CommandResult:
   """Executes an equery command, returns the result of the cmd.
 
   Args:
@@ -1895,12 +1934,19 @@
     cmd += ['--include-masked']
   cmd += packages_list
   return cros_build_lib.run(
-      cmd, extra_env=extra_env, print_cmd=False, capture_output=True,
-      check=check, encoding='utf-8')
+      cmd,
+      extra_env=extra_env,
+      print_cmd=False,
+      capture_output=True,
+      check=check,
+      encoding='utf-8')
 
 
-def FindEbuildsForPackages(packages_list, sysroot, include_masked=False,
-                           extra_env=None, check=False):
+def FindEbuildsForPackages(packages_list,
+                           sysroot,
+                           include_masked=False,
+                           extra_env=None,
+                           check=False):
   """Returns paths to the ebuilds for the packages in |packages_list|.
 
   Args:
@@ -1922,8 +1968,8 @@
   if not packages_list:
     return {}
 
-  result = _EqueryWhich(packages_list, sysroot, include_masked,
-                        extra_env=extra_env, check=check)
+  result = _EqueryWhich(
+      packages_list, sysroot, include_masked, extra_env=extra_env, check=check)
   if result.returncode:
     return {}
 
@@ -1936,8 +1982,8 @@
     path_category, path_package_name, _ = SplitEbuildPath(ebuild_path)
     if not ((cpv.category is None or path_category == cpv.category) and
             cpv.package.startswith(path_package_name)):
-      mismatches.append(
-          "%s doesn't match %s" % (ebuild_path, full_package_name))
+      mismatches.append("%s doesn't match %s" %
+                        (ebuild_path, full_package_name))
 
   assert not mismatches, ('Detected mismatches between the package & '
                           'corresponding ebuilds: %s' % '\n'.join(mismatches))
@@ -1945,8 +1991,11 @@
   return ret
 
 
-def FindEbuildForPackage(pkg_str, sysroot, include_masked=False,
-                         extra_env=None, check=False):
+def FindEbuildForPackage(pkg_str,
+                         sysroot,
+                         include_masked=False,
+                         extra_env=None,
+                         check=False):
   """Returns a path to an ebuild responsible for package matching |pkg_str|.
 
   Args:
@@ -1961,14 +2010,32 @@
   Returns:
     Path to ebuild for this package.
   """
-  ebuilds_map = FindEbuildsForPackages(
-      [pkg_str], sysroot, include_masked, extra_env, check=check)
+  ebuilds_map = FindEbuildsForPackages([pkg_str],
+                                       sysroot,
+                                       include_masked,
+                                       extra_env,
+                                       check=check)
   if not ebuilds_map:
     return None
   return ebuilds_map[pkg_str]
 
 
-def _EqueryDepgraph(pkg_str: str, sysroot: str,
+def FindEbuildsForOverlays(
+    overlays: List[Union[str, os.PathLike]]) -> Iterator[Path]:
+  """Get paths to ebuilds using the given overlay paths.
+
+  Args:
+    overlays: A list of overlay paths to get ebuilds for.
+
+  Returns:
+    A generator of paths to ebuild files.
+  """
+  return itertools.chain.from_iterable(
+      Path(x).rglob('*.ebuild') for x in overlays)
+
+
+def _EqueryDepgraph(pkg_str: str,
+                    sysroot: str,
                     depth: int = 0) -> cros_build_lib.CommandResult:
   """Executes equery depgraph to find dependencies.
 
@@ -1989,8 +2056,8 @@
   ]
 
   cmd += [pkg_str]
-  return cros_build_lib.run(cmd, print_cmd=False, capture_output=True,
-                            check=True, encoding='utf-8')
+  return cros_build_lib.run(
+      cmd, print_cmd=False, capture_output=True, check=True, encoding='utf-8')
 
 
 def GetFlattenedDepsForPackage(pkg_str, sysroot='/', depth=0):
@@ -2035,30 +2102,35 @@
 
 
 def _Qlist(
-    pkg_str: str,
+    args: List[str],
     board: Optional[str] = None,
     buildroot: str = constants.SOURCE_ROOT) -> cros_build_lib.CommandResult:
-  """Use qlist to get USE flags for installed packages matching |pkg_str|.
+  """Run qlist with the given args.
 
   Args:
-    pkg_str: The package name with optional category, version, and slot.
+    args: The qlist arguments.
     board: The board to inspect.
     buildroot: Source root to find overlays.
 
   Returns:
-    result (cros_build_lib.CommandResult)
+    The command result
   """
-  cmd = ['qlist']
-  if board:
-    cmd = ['qlist-%s' % board]
+  cmd = [f'qlist-{board}' if board else 'qlist']
+  # Simplify output.
+  cmd += ['-Cq']
+  cmd += args
 
-  cmd += ['-CqU', pkg_str]
   return cros_build_lib.run(
-      cmd, enter_chroot=True, capture_output=True, check=False,
-      encoding='utf-8', cwd=buildroot)
+      cmd,
+      enter_chroot=True,
+      capture_output=True,
+      check=False,
+      encoding='utf-8',
+      cwd=buildroot)
 
 
-def GetInstalledPackageUseFlags(pkg_str, board=None,
+def GetInstalledPackageUseFlags(pkg_str,
+                                board=None,
                                 buildroot=constants.SOURCE_ROOT):
   """Gets the list of USE flags for installed packages matching |pkg_str|.
 
@@ -2071,7 +2143,7 @@
     A dictionary with the key being a package CP and the value being the list
     of USE flags for that package.
   """
-  result = _Qlist(pkg_str, board, buildroot)
+  result = _Qlist(['-U', pkg_str], board, buildroot)
   use_flags = {}
   if result.returncode == 0:
     for line in result.output.splitlines():
@@ -2128,15 +2200,18 @@
     result (cros_build_lib.CommandResult)
   """
   emerge = 'emerge-%s' % board if board else 'emerge'
-  cmd = [emerge, '-p', '--cols', '--quiet', '--root', '/mnt/empty', '-e',
-         package]
+  cmd = [
+      emerge, '-p', '--cols', '--quiet', '--root', '/mnt/empty', '-e', package
+  ]
   return cros_build_lib.run(
-      cmd, cwd=buildroot, enter_chroot=True,
-      capture_output=True, encoding='utf-8')
+      cmd,
+      cwd=buildroot,
+      enter_chroot=True,
+      capture_output=True,
+      encoding='utf-8')
 
 
-def GetPackageDependencies(board, package,
-                           buildroot=constants.SOURCE_ROOT):
+def GetPackageDependencies(board, package, buildroot=constants.SOURCE_ROOT):
   """Returns the depgraph list of packages for a board and package."""
   emerge_output = _EmergeBoard(board, package, buildroot).stdout.splitlines()
   packages = []
@@ -2153,18 +2228,6 @@
   return packages
 
 
-def GetFullAndroidPortagePackageName(android_package_name):
-  """Returns the full portage package name for the given android package.
-
-  Args:
-    android_package_name: Android package name. E.g. android-container.
-
-  Returns:
-    Full portage package name. E.g. chromeos-base/android-container.
-  """
-  return '%s/%s' % (constants.CHROMEOS_BASE, android_package_name)
-
-
 def GetRepositoryFromEbuildInfo(info):
   """Parse output of the result of `ebuild <ebuild_path> info`
 
@@ -2172,10 +2235,10 @@
    CROS_WORKON_SRCDIR=("/mnt/host/source/src/platform2")
    CROS_WORKON_PROJECT=("chromiumos/platform2")
   """
-  srcdir_match = re.search(r'^CROS_WORKON_SRCDIR=(\(".*"\))$',
-                           info, re.MULTILINE)
-  project_match = re.search(r'^CROS_WORKON_PROJECT=(\(".*"\))$',
-                            info, re.MULTILINE)
+  srcdir_match = re.search(r'^CROS_WORKON_SRCDIR=(\(".*"\))$', info,
+                           re.MULTILINE)
+  project_match = re.search(r'^CROS_WORKON_PROJECT=(\(".*"\))$', info,
+                            re.MULTILINE)
   if not srcdir_match or not project_match:
     return None
 
@@ -2184,12 +2247,13 @@
   if len(srcdirs) != len(projects):
     return None
 
-  return [RepositoryInfoTuple(srcdir, project)
-          for srcdir, project in zip(srcdirs, projects)]
+  return [
+      RepositoryInfoTuple(srcdir, project)
+      for srcdir, project in zip(srcdirs, projects)
+  ]
 
 
-def _EbuildInfo(ebuild_path: str,
-                sysroot: str) -> cros_build_lib.CommandResult:
+def _EbuildInfo(ebuild_path: str, sysroot: str) -> cros_build_lib.CommandResult:
   """Get ebuild info for <ebuild_path>.
 
   Args:
@@ -2199,8 +2263,8 @@
   Returns:
     result (cros_build_lib.CommandResult)
   """
-  cmd = (cros_build_lib.GetSysrootToolPath(sysroot, 'ebuild'),
-         ebuild_path, 'info')
+  cmd = (cros_build_lib.GetSysrootToolPath(sysroot,
+                                           'ebuild'), ebuild_path, 'info')
   return cros_build_lib.run(
       cmd, capture_output=True, print_cmd=False, check=False, encoding='utf-8')
 
@@ -2311,8 +2375,8 @@
   with osutils.TempDir() as tempdir:
     output_file = os.path.join(tempdir, 'has_prebuilt.json')
     cmd += ['--output', output_file]
-    result = cros_build_lib.run(cmd, enter_chroot=True, extra_env=extra_env,
-                                check=False)
+    result = cros_build_lib.run(
+        cmd, enter_chroot=True, extra_env=extra_env, check=False)
 
     if result.returncode:
       logging.warning('Error when checking for prebuilts: %s', result.stderr)
@@ -2373,12 +2437,11 @@
   return cros_build_lib.run([_GetPortageq(board, sysroot)] + command, **kwargs)
 
 
-def PortageqBestVisible(
-    atom: str,
-    board: Optional[str] = None,
-    sysroot: Optional[str] = None,
-    pkg_type: str = 'ebuild',
-    cwd: str = None) -> package_info.PackageInfo:
+def PortageqBestVisible(atom: str,
+                        board: Optional[str] = None,
+                        sysroot: Optional[str] = None,
+                        pkg_type: str = 'ebuild',
+                        cwd: str = None) -> package_info.PackageInfo:
   """Get the best visible ebuild CPV for the given atom.
 
   Args:
@@ -2432,7 +2495,9 @@
   elif not variable:
     raise ValueError('Variable must not be empty.')
 
-  result = PortageqEnvvars([variable], board=board, sysroot=sysroot,
+  result = PortageqEnvvars([variable],
+                           board=board,
+                           sysroot=sysroot,
                            allow_undefined=allow_undefined)
   return result[variable]
 
@@ -2463,16 +2528,16 @@
     return {}
 
   try:
-    result = _Portageq(['envvar', '-v'] + variables, board=board,
-                       sysroot=sysroot)
+    result = _Portageq(
+        ['envvar', '-v'] + variables, board=board, sysroot=sysroot)
   except cros_build_lib.RunCommandError as e:
     if e.result.returncode != 1:
       # Actual error running command, raise.
       raise e
     elif not allow_undefined:
       # Error for undefined variable.
-      raise PortageqError(
-          'One or more variables undefined: %s' % e.result.output)
+      raise PortageqError('One or more variables undefined: %s' %
+                          e.result.output)
     else:
       # Undefined variable but letting it slide.
       result = e.result
@@ -2498,8 +2563,10 @@
     sysroot = build_target_lib.get_default_sysroot_path(board)
   # Exit codes 0/1+ indicate "have"/"don't have".
   # Normalize them into True/False values.
-  result = _Portageq(['has_version', sysroot, category_package], board=board,
-                     sysroot=sysroot, check=False)
+  result = _Portageq(['has_version', sysroot, category_package],
+                     board=board,
+                     sysroot=sysroot,
+                     check=False)
   return not result.returncode
 
 
@@ -2532,8 +2599,8 @@
     category, pv = package.split('/')
     installed_package = db.GetInstalledPackage(category, pv)
     if not installed_package:
-      raise PackageNotFoundError('Unable to locate package %s in %s' % (package,
-                                                                        root))
+      raise PackageNotFoundError('Unable to locate package %s in %s' %
+                                 (package, root))
     yield installed_package
 
 
@@ -2587,8 +2654,5 @@
   if chroot:
     chroot_args = chroot.get_enter_args()
 
-  command = [
-      'ebuild', ebuild_path, 'manifest', '--force'
-  ]
-  return cros_build_lib.run(command, enter_chroot=True,
-                            chroot_args=chroot_args)
+  command = ['ebuild', ebuild_path, 'manifest', '--force']
+  return cros_build_lib.run(command, enter_chroot=True, chroot_args=chroot_args)
diff --git a/lib/portage_util_unittest.py b/lib/portage_util_unittest.py
index d955ecb..e38137b 100644
--- a/lib/portage_util_unittest.py
+++ b/lib/portage_util_unittest.py
@@ -6,6 +6,7 @@
 
 import json
 import os
+from pathlib import Path
 
 from chromite.lib import constants
 from chromite.lib import cros_build_lib
@@ -1391,6 +1392,13 @@
     fake_files = [(f[0], f[1].lstrip('/')) for f in fake_files]
     self.assertEqual(fake_files, lst)
 
+  def testPackageInfo(self):
+    """Verify construction and self consistency of the PackageInfo."""
+    portage_db = portage_util.PortageDB(self.fake_chroot)
+    for pkg in portage_db.InstalledPackages():
+      self.assertEqual(pkg.category, pkg.package_info.category)
+      self.assertEqual(pkg.pf, pkg.package_info.pvr)
+
 
 class InstalledPackageTest(cros_test_lib.TempDirTestCase):
   """InstalledPackage class tests outside a PortageDB."""
@@ -1734,3 +1742,28 @@
         expected,
         portage_util.GetPackageDependencies(None,
                                             'target-chromium-os-sdk'))
+
+
+class FindEbuildsForOverlaysTest(cros_test_lib.MockTempDirTestCase):
+  """Tests for FindEbuildsForOverlays."""
+
+  def setUp(self):
+    file_layout = (cros_test_lib.Directory('package1/bar1',
+                                           ['bar1-1.0.ebuild']),
+                   cros_test_lib.Directory('package2/bar2',
+                                           ['bar2-2.0.ebuild']))
+    cros_test_lib.CreateOnDiskHierarchy(self.tempdir, file_layout)
+
+  def testFindEbuildsForOverlaysOutput(self):
+    mock_overlay_paths = [
+        Path(self.tempdir) / 'package1' / 'bar1',
+        Path(self.tempdir) / 'package2' / 'bar2',
+    ]
+    expected_ebuilds = [
+        Path(self.tempdir) / 'package1' / 'bar1' / 'bar1-1.0.ebuild',
+        Path(self.tempdir) / 'package2' / 'bar2' / 'bar2-2.0.ebuild',
+    ]
+
+    ebuilds = yield from portage_util.FindEbuildsForOverlays(mock_overlay_paths)
+
+    self.assertEqual(expected_ebuilds, ebuilds)
diff --git a/lib/remoteexec_util.py b/lib/remoteexec_util.py
new file mode 100644
index 0000000..75b1fc5
--- /dev/null
+++ b/lib/remoteexec_util.py
@@ -0,0 +1,61 @@
+# Copyright 2021 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Module to use remoteexec from builders."""
+
+import getpass
+import os
+
+from chromite.lib import constants
+
+
+class Remoteexec(object):
+  """Interface to use remoteexec on bots."""
+
+  def __init__(self, reclient_dir, reproxy_cfg_file):
+    """Initializes a Remoteexec instance.
+
+    Args:
+      reclient_dir: Path to the re-client directory that contains
+        the reproxy, bootstrap, rewrapper binaries.
+      reproxy_cfg_file: Path to the config file for starting reproxy.
+    """
+
+    if not os.path.isdir(reclient_dir):
+      raise ValueError(
+          f'reclient_dir does not point to a directory: {reclient_dir}')
+
+    self.reclient_dir = reclient_dir
+
+    # TODO(crbug.com/1256966): `reproxy_cfg_file` is either the full path
+    # of a config generated by recipes or the name of a committed file
+    # in `chromite/sdk/reclient_cfgs. When other builders, other than the
+    # initial informational builder, are added, they should all be generated
+    # by recipes rather than committed.
+    if not os.path.exists(reproxy_cfg_file):
+      reproxy_cfg_file = os.path.join(
+          constants.CHROMITE_DIR, 'sdk', 'reclient_cfgs', reproxy_cfg_file)
+      if not os.path.exists(reproxy_cfg_file):
+        raise ValueError(
+            f'reproxy_cfg_file does not exist: {reproxy_cfg_file}')
+    self.reproxy_cfg_file = reproxy_cfg_file
+
+  def __eq__(self, other):
+    if self.__class__ is other.__class__:
+      return (self.reclient_dir == other.reclient_dir
+              and self.reproxy_cfg_file == other.reproxy_cfg_file)
+    return NotImplemented
+
+  def GetChrootExtraEnv(self):
+    """Extra env vars set to do remoteexec inside chroot."""
+    # These paths should match the paths in chroot that the
+    # reclient directory and reproxy config file get mapped to
+    # in sdk_lib/enter_chroot.sh
+    reclient_dir = os.path.join('/home', getpass.getuser(), 'reclient')
+    reproxy_cfg_file = os.path.join('/home', getpass.getuser(),
+                                    'reclient_cfgs', 'reproxy_chroot.cfg')
+    result = {'RECLIENT_DIR': reclient_dir,
+              'REPROXY_CFG': reproxy_cfg_file}
+
+    return result
diff --git a/lib/remoteexec_util_unittest.py b/lib/remoteexec_util_unittest.py
new file mode 100644
index 0000000..475702a
--- /dev/null
+++ b/lib/remoteexec_util_unittest.py
@@ -0,0 +1,30 @@
+# Copyright 2021 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Unittests for remoteexec_util.py"""
+
+import os
+
+from chromite.lib import cros_test_lib
+from chromite.lib import osutils
+from chromite.lib import remoteexec_util
+
+
+class TestRemoteexecUtil(cros_test_lib.MockTempDirTestCase):
+  """Tests for remoteexec_util."""
+
+  def testExtraEnvCustomChroot(self):
+    """Test that the extra chroot envs for remoteexec are correct."""
+    reclient_dir = os.path.join(self.tempdir, 'cipd/rbe')
+    reproxy_cfg_file = os.path.join(self.tempdir,
+                                    'reclient_cfgs/reproxy_config.cfg')
+
+    osutils.SafeMakedirs(reclient_dir)
+    osutils.SafeMakedirs(reproxy_cfg_file)
+
+    remote = remoteexec_util.Remoteexec(reclient_dir, reproxy_cfg_file)
+
+    chroot_env = remote.GetChrootExtraEnv()
+    self.assertEndsWith(chroot_env['RECLIENT_DIR'], '/reclient')
+    self.assertEndsWith(chroot_env['REPROXY_CFG'], '/reproxy_chroot.cfg')
diff --git a/lib/sudo.py b/lib/sudo.py
index 9a67a8b..76e920e 100644
--- a/lib/sudo.py
+++ b/lib/sudo.py
@@ -14,7 +14,7 @@
 from chromite.lib import cros_build_lib
 
 
-class SudoKeepAlive(cros_build_lib.MasterPidContextManager):
+class SudoKeepAlive(cros_build_lib.PrimaryPidContextManager):
   """Keep sudo auth cookie fresh.
 
   This refreshes the sudo auth cookie; this is implemented this
@@ -30,7 +30,7 @@
       ttyless_sudo: Whether to update the tty-less cookie.
       repeat_interval: In minutes, the frequency to run the update.
     """
-    cros_build_lib.MasterPidContextManager.__init__(self)
+    cros_build_lib.PrimaryPidContextManager.__init__(self)
     self._ttyless_sudo = ttyless_sudo
     self._repeat_interval = repeat_interval
     self._proc = None
diff --git a/lib/sysroot_lib.py b/lib/sysroot_lib.py
index ea1465b..87c3713 100644
--- a/lib/sysroot_lib.py
+++ b/lib/sysroot_lib.py
@@ -95,8 +95,6 @@
 _MAKE_CONF_USER = 'etc/make.conf.user'
 _MAKE_CONF_HOST_SETUP = 'etc/make.conf.host_setup'
 
-_CONFIGURATION_PATH = _MAKE_CONF_BOARD_SETUP
-
 _CACHE_PATH = 'var/cache/edb/chromeos'
 
 _CHROMIUMOS_OVERLAY = '/usr/local/portage/chromiumos'
@@ -274,7 +272,13 @@
 
   def __init__(self, path):
     self.path = path
-    self._config_file = self.Path(_CONFIGURATION_PATH)
+
+    # Read config from _MAKE_CONF which also pulls in config from
+    # _MAKE_CONF_BOARD_SETUP, but only write any config overrides directly to
+    # _MAKE_CONF_BOARD_SETUP.
+    self._config_file_read = self.Path(_MAKE_CONF)
+    self._config_file_write = self.Path(_MAKE_CONF_BOARD_SETUP)
+
     self._cache_file = self.Path(_CACHE_PATH)
     self._cache_file_lock = self._cache_file + '.lock'
 
@@ -317,8 +321,11 @@
       field: Field from the standard configuration file to get.
         One of STANDARD_FIELD_* from above.
     """
-    return osutils.SourceEnvironment(self._config_file,
-                                     [field], multiline=True).get(field)
+    # We want to source from within the config's directory as the config
+    # itself may source other scripts using a relative path.
+    with osutils.ChdirContext(Path(self._config_file_read).parent):
+      return osutils.SourceEnvironment(self._config_file_read,
+                                       [field], multiline=True).get(field)
 
   def GetCachedField(self, field):
     """Returns the value of |field| in the sysroot cache file.
@@ -378,7 +385,7 @@
     return self.GetCachedField(CACHED_FIELD_PROFILE_OVERRIDE) or DEFAULT_PROFILE
 
   @property
-  def build_target_overlays(self) -> List[str]:
+  def board_overlay(self) -> List[str]:
     """The BOARD_OVERLAY standard field as a list.
 
     The BOARD_OVERLAY field is set on creation, and stores the list of overlays
@@ -391,7 +398,43 @@
     return self.GetStandardField(STANDARD_FIELD_BOARD_OVERLAY).split()
 
   @property
-  def overlays(self) -> List[str]:
+  def _build_target_overlays(self) -> List[Path]:
+    """Overlays for the build target itself."""
+    prefix = f'overlay-{self.build_target_name}'
+    return [x for x in self.get_overlays() if x.name.startswith(prefix)]
+
+  @property
+  def build_target_overlay(self) -> Optional[Path]:
+    """The most specific build target overlay for the sysroot."""
+    # Choose the longest as a proxy for the most specific. This should only ever
+    # be choosing between overlay-x and overlay-x-private, but we'll need better
+    # logic here if we have any cases with more than that.
+    overlays = self._build_target_overlays
+    overlay = max(overlays, key=lambda x: len(x.name)) if overlays else None
+    return overlay
+
+  @property
+  def chipset(self) -> Optional[str]:
+    """The chipset for the sysroot's build target."""
+    overlays = [x for x in self.get_overlays() if x.name.startswith('chipset-')]
+    if not overlays:
+      return None
+
+    # Choose the longest as a proxy for the most specific. This should at most
+    # be choosing between chipset-x and chipset-x-private, but we'll need better
+    # logic here if we have any cases with more than that.
+    overlay = max(overlays, key=lambda x: len(x.name))
+    chipset = overlay.name
+
+    # TODO(python 3.9): string.removeprefix & string.removesuffix instead.
+    if chipset.startswith('chipset-'):
+      chipset = chipset[len('chipset-'):]
+    if chipset.endswith('-private'):
+      chipset = chipset[:-len('-private')]
+    return chipset
+
+  @property
+  def portdir_overlay(self) -> List[str]:
     """The PORTDIR_OVERLAY field as a list.
 
     The PORTDIR_OVERLAY field is set on creation, and stores the list of all
@@ -400,8 +443,19 @@
     return self.GetStandardField(STANDARD_FIELD_PORTDIR_OVERLAY).split()
 
   @property
-  def use_flags(self):
-    return portage_util.PortageqEnvvar('USE', sysroot=self.path)
+  def use_flags(self) -> List[str]:
+    """Get all USE flags for the sysroot."""
+    return portage_util.PortageqEnvvar('USE', sysroot=self.path).split()
+
+  @property
+  def features(self) -> List[str]:
+    """Get all FEATURES for the sysroot."""
+    return portage_util.PortageqEnvvar('FEATURES', sysroot=self.path).split()
+
+  @property
+  def portage_logdir(self) -> str:
+    """Get the PORTAGE_LOGDIR property for this sysroot."""
+    return portage_util.PortageqEnvvar('PORTAGE_LOGDIR', sysroot=self.path)
 
   def get_overlays(self,
                    build_target_only: bool = False,
@@ -418,7 +472,7 @@
         as absolute paths.
     """
     overlays = (
-        self.build_target_overlays if build_target_only else self.overlays)
+        self.board_overlay if build_target_only else self.portdir_overlay)
     overlay_paths = [Path(x) for x in overlays]
     if relative:
       return [
@@ -536,8 +590,7 @@
     Args:
       board (str): The name of the board being setup in the sysroot.
     """
-    osutils.WriteFile(self.Path(_MAKE_CONF_BOARD_SETUP),
-                      self.GenerateBoardSetupConfig(board), sudo=True)
+    self.WriteConfig(self.GenerateBoardSetupConfig(board))
 
   def InstallMakeConfUser(self):
     """Make sure the sysroot has the make.conf.user file.
@@ -610,7 +663,7 @@
     Args:
       config: configuration to use.
     """
-    osutils.WriteFile(self._config_file, config, makedirs=True, sudo=True)
+    osutils.WriteFile(self._config_file_write, config, makedirs=True, sudo=True)
 
   def GenerateBoardMakeConf(self, accepted_licenses=None):
     """Generates the board specific make.conf.
@@ -648,10 +701,8 @@
                                    'gs_fetch_binpkg')
     gsutil_cmd = '%s \\"${URI}\\" \\"${DISTDIR}/${FILE}\\"' % gs_fetch_binpkg
     config.append('BOTO_CONFIG="%s"' % boto_config)
-    # Retry the fetch if it fails
-    config.append('FETCHCOMMAND_GS="bash -c \''
-                  'export BOTO_CONFIG=%s; %s || %s\'"'
-                  % (boto_config, gsutil_cmd, gsutil_cmd))
+    config.append('FETCHCOMMAND_GS="bash -c \'BOTO_CONFIG=%s %s\'"'
+                  % (boto_config, gsutil_cmd))
     config.append('RESUMECOMMAND_GS="$FETCHCOMMAND_GS"')
 
     if accepted_licenses:
@@ -784,7 +835,7 @@
     hook_glob = os.path.join(constants.CROSUTILS_DIR, 'hooks', '*')
     for filename in glob.glob(hook_glob):
       linkpath = self.Path('etc', 'portage', 'hooks',
-                            os.path.basename(filename))
+                           os.path.basename(filename))
       osutils.SafeSymlink(filename, linkpath, sudo=True)
 
   def UpdateToolchain(self, board, local_init=True):
diff --git a/lib/sysroot_lib_unittest.py b/lib/sysroot_lib_unittest.py
index 4ef2e51..0cd628f 100644
--- a/lib/sysroot_lib_unittest.py
+++ b/lib/sysroot_lib_unittest.py
@@ -5,6 +5,7 @@
 """Tests for the sysroot library."""
 
 import os
+from typing import Iterable, List, Optional, Tuple
 
 from chromite.api.gen.chromiumos import common_pb2
 from chromite.lib import chroot_lib
@@ -14,6 +15,7 @@
 from chromite.lib import osutils
 from chromite.lib import sysroot_lib
 from chromite.lib import toolchain
+from chromite.lib import unittest_lib
 from chromite.lib.parser import package_info
 
 
@@ -29,14 +31,22 @@
     osutils.SafeMakedirs(sysroot_path)
     self.sysroot = sysroot_lib.Sysroot(sysroot_path)
     self.relative_sysroot = sysroot_lib.Sysroot('sysroot')
+    # make.conf needs to exist to correctly read back config.
+    unittest_lib.create_stub_make_conf(sysroot_path)
 
-  def _writeOverlays(self, board_overlays=None, portdir_overlays=None):
+  def _writeOverlays(self,
+                     board_overlays: Optional[Iterable[str]] = None,
+                     portdir_overlays: Optional[Iterable[str]] = None,
+                     board: str = None) -> Tuple[List[str], List[str]]:
     """Helper function to write board and portdir overlays for the sysroot.
 
     By default uses one fake board overlay, and the chromiumos and portage
     stable overlays. Set the arguments to an empty list to set no values for
     that field. When not explicitly set, |portdir_overlays| includes all values
     in |board_overlays|.
+
+    Returns:
+      The board overlays, and the portdir overlays.
     """
     if board_overlays is None:
       board_overlays = ['overlay/board']
@@ -45,8 +55,9 @@
           constants.CHROMIUMOS_OVERLAY_DIR, constants.PORTAGE_STABLE_OVERLAY_DIR
       ] + board_overlays
 
-    board_field = sysroot_lib.STANDARD_FIELD_BOARD_OVERLAY
+    board_overlays_field = sysroot_lib.STANDARD_FIELD_BOARD_OVERLAY
     portdir_field = sysroot_lib.STANDARD_FIELD_PORTDIR_OVERLAY
+    board_field = sysroot_lib.STANDARD_FIELD_BOARD_USE
 
     board_values = [
         f'{constants.CHROOT_SOURCE_ROOT}/{x}' for x in board_overlays
@@ -60,9 +71,11 @@
 
     config_values = {}
     if board_values:
-      config_values[board_field] = board_value
+      config_values[board_overlays_field] = board_value
     if portdir_values:
       config_values[portdir_field] = portdir_value
+    if board:
+      config_values[board_field] = board
 
     config = '\n'.join(f'{k}="{v}"' for k, v in config_values.items())
     self.sysroot.WriteConfig(config)
@@ -155,13 +168,52 @@
     """Test the board_overlay property."""
     board_overlays, _portdir_overlays = self._writeOverlays()
 
-    self.assertEqual(board_overlays, self.sysroot.build_target_overlays)
+    self.assertEqual(sorted(board_overlays), sorted(self.sysroot.board_overlay))
+
+  def testBuildTargetOverlays(self):
+    """Tests for populated _build_target_overlay[s]."""
+    private = '/path/to/overlay-x-private'
+    expected = ['/path/to/overlay-x', private]
+    overlays = expected + ['/path/to/chromeos-overlay']
+    self._writeOverlays(overlays, board='x')
+
+    # pylint: disable=protected-access
+    results = [str(x) for x in self.sysroot._build_target_overlays]
+    self.assertEqual(len(expected), len(results))
+    for current in expected:
+      self.assertTrue(any(result.endswith(current) for result in results))
+
+    self.assertTrue(str(self.sysroot.build_target_overlay).endswith(private))
+
+  def testNoBuildTargetOverlay(self):
+    """Test for no standard build target overlay."""
+    self._writeOverlays(['/path/to/chromeos-overlay', '/path/to/chipset-x'])
+
+    # pylint: disable=protected-access
+    self.assertEqual(0, len(self.sysroot._build_target_overlays))
+    self.assertIsNone(self.sysroot.build_target_overlay)
+
+  def testChipset(self):
+    """Test for extracting a valid chipset."""
+    expected = 'foo'
+    chipsets = [
+        f'/path/to/chipset-{expected}', f'/path/to/chipset-{expected}-private'
+    ]
+    all_overlays = chipsets + ['/path/to/chromeos-overlay']
+    self._writeOverlays(all_overlays)
+
+    self.assertEqual(expected, self.sysroot.chipset)
+
+  def testNoChipset(self):
+    """Test for handling no retrievable chipset value."""
+    self._writeOverlays(['/path/to/chromeos-overlay', '/path/to/overlay-board'])
+    self.assertIsNone(self.sysroot.chipset)
 
   def testOverlays(self):
     """Test the overlays property."""
     _board_overlays, portdir_overlays = self._writeOverlays()
 
-    self.assertEqual(portdir_overlays, self.sysroot.overlays)
+    self.assertEqual(portdir_overlays, self.sysroot.portdir_overlay)
 
   def testGetOverlays(self):
     """Test the get_overlays function."""
diff --git a/lib/tee.py b/lib/tee.py
index 9b0f7bd..c8e3f64 100644
--- a/lib/tee.py
+++ b/lib/tee.py
@@ -183,12 +183,12 @@
       os._exit(0)
 
 
-class Tee(cros_build_lib.MasterPidContextManager):
+class Tee(cros_build_lib.PrimaryPidContextManager):
   """Class that handles tee-ing output to a file."""
 
   def __init__(self, output_file):
     """Initializes object with path to log file."""
-    cros_build_lib.MasterPidContextManager.__init__(self)
+    cros_build_lib.PrimaryPidContextManager.__init__(self)
     self._file = output_file
     self._old_stdout = None
     self._old_stderr = None
diff --git a/lib/toolchain_list.py b/lib/toolchain_list.py
index 4cfc4cd..d728dc2 100644
--- a/lib/toolchain_list.py
+++ b/lib/toolchain_list.py
@@ -121,6 +121,7 @@
           'sdk': True,
           'crossdev': '',
           'default': False,
+          'have-binpkg': True,
       }
       settings.update(targets[target])
       targets[target] = settings
diff --git a/lib/toolchain_unittest.py b/lib/toolchain_unittest.py
index 2ef575d..2b7f1fd 100644
--- a/lib/toolchain_unittest.py
+++ b/lib/toolchain_unittest.py
@@ -36,9 +36,14 @@
         'default': False,
         'a setting': 'bonus value',
         'stable': True,
+        'have-binpkg': True,
     },
-    'extra-toolchain': {'sdk': True, 'crossdev': '', 'default': True},
-    'base-target-name': {'sdk': True, 'crossdev': '', 'default': False},
+    'extra-toolchain': {
+        'sdk': True, 'crossdev': '', 'default': True, 'have-binpkg': True,
+    },
+    'base-target-name': {
+        'sdk': True, 'crossdev': '', 'default': False, 'have-binpkg': True,
+    },
 }
 
 
diff --git a/lib/toolchain_util.py b/lib/toolchain_util.py
index 06d61b7..fd8e22a 100644
--- a/lib/toolchain_util.py
+++ b/lib/toolchain_util.py
@@ -15,17 +15,14 @@
 import shutil
 from typing import Iterable, Optional
 
-from chromite.cbuildbot import afdo
 from chromite.lib import alerts
 from chromite.lib import constants
 from chromite.lib import cros_build_lib
-from chromite.lib import git
 from chromite.lib import gob_util
 from chromite.lib import gs
 from chromite.lib import osutils
 from chromite.lib import path_util
 from chromite.lib import portage_util
-from chromite.lib import timeout_util
 from chromite.lib.parser import package_info
 from chromite.utils import pformat
 
@@ -50,15 +47,12 @@
 # the future.
 ORDERFILE_GS_URL_UNVETTED = (
     'gs://chromeos-toolchain-artifacts/orderfile/unvetted')
-ORDERFILE_GS_URL_VETTED = 'gs://chromeos-prebuilt/afdo-job/orderfiles/vetted'
 BENCHMARK_AFDO_GS_URL = (
     'gs://chromeos-toolchain-artifacts/afdo/unvetted/benchmark')
 CWP_AFDO_GS_URL = 'gs://chromeos-prebuilt/afdo-job/cwp/chrome/'
 KERNEL_PROFILE_URL = 'gs://chromeos-prebuilt/afdo-job/cwp/kernel/'
 AFDO_GS_URL_VETTED = 'gs://chromeos-prebuilt/afdo-job/vetted/'
 KERNEL_AFDO_GS_URL_VETTED = os.path.join(AFDO_GS_URL_VETTED, 'kernel')
-BENCHMARK_AFDO_GS_URL_VETTED = os.path.join(AFDO_GS_URL_VETTED, 'benchmarks')
-CWP_AFDO_GS_URL_VETTED = os.path.join(AFDO_GS_URL_VETTED, 'cwp')
 RELEASE_AFDO_GS_URL_VETTED = os.path.join(AFDO_GS_URL_VETTED, 'release')
 
 # Constants
@@ -77,7 +71,7 @@
 
 # How old can the Kernel AFDO data be? (in days).
 KERNEL_ALLOWED_STALE_DAYS = 42
-# How old can the Kernel AFDO data be before sheriff got noticed? (in days).
+# How old can the Kernel AFDO data be before detective got noticed? (in days).
 KERNEL_WARN_STALE_DAYS = 14
 
 # For merging release Chrome profiles.
@@ -94,14 +88,7 @@
 # at least 4GB of memory.
 #
 # This must be consistent with the definitions in autotest.
-AFDO_DATA_GENERATORS_LLVM = ('chell')
 CHROME_AFDO_VERIFIER_BOARDS = {'chell': 'atom', 'eve': 'bigcore'}
-KERNEL_AFDO_VERIFIER_BOARDS = {
-    'chell': '3.18',
-    'eve': '4.4',
-    'octopus': '4.14',
-    'banon': '4.19'
-}
 
 AFDO_ALERT_RECIPIENTS = ['chromeos-toolchain-oncall1@google.com']
 
@@ -110,12 +97,7 @@
                                    constants.CHROMIUMOS_OVERLAY_DIR)
 
 # RegExps
-# NOTE: These regexp are copied from cbuildbot/afdo.py. Keep two copies
-# until deployed and then remove the one in cbuildbot/afdo.py.
-CHROOT_ROOT = os.path.join('%(build_root)s', constants.DEFAULT_CHROOT_DIR)
-CHROOT_TMP_DIR = os.path.join('%(root)s', 'tmp')
-AFDO_VARIABLE_REGEX = r'AFDO_FILE\["%s"\]'
-AFDO_ARTIFACT_EBUILD_REGEX = r'^(?P<bef>%s=)(?P<name>("[^"]*"|.*))(?P<aft>.*)'
+AFDO_ARTIFACT_EBUILD_REGEX = r'(?P<bef>%s=)(?P<name>("[^"]*"|.*))(?P<aft>.*)'
 AFDO_ARTIFACT_EBUILD_REPL = r'\g<bef>"%s"\g<aft>'
 
 ChromeVersion = collections.namedtuple(
@@ -209,18 +191,10 @@
   """Error for helper functions related to profile naming."""
 
 
-class GenerateBenchmarkAFDOProfilesError(Error):
-  """Error for GenerateBenchmarkAFDOProfiles class."""
-
-
 class UpdateEbuildWithAFDOArtifactsError(Error):
   """Error for UpdateEbuildWithAFDOArtifacts class."""
 
 
-class PublishVettedAFDOArtifactsError(Error):
-  """Error for publishing vetted afdo artifacts."""
-
-
 def _ParseBenchmarkProfileName(profile_name):
   """Parse the name of a benchmark profile for Chrome.
 
@@ -302,44 +276,6 @@
       is_merged=False), CWPProfileVersion(*[int(x) for x in cwp_groups]))
 
 
-def _FindEbuildPath(package, buildroot=None, board=None):
-  """Find the path to ebuild (in chroot or outside).
-
-  Args:
-    package: Name of the package. chromeos-chrome or chromeos-kernel-X_XX.
-    buildroot: Optional. The path to build root, when used outside chroot.
-    When omitted, the return path is relative inside chroot.
-    board: Optional. A string of the name of the board.
-
-  Returns:
-    The full path to the versioned ebuild file. The path is either
-    relative inside chroot, or outside chroot, depending on the buildroot arg.
-  """
-  valid_package_names = [
-      'chromeos-kernel-' + x.replace('.', '_')
-      for x in KERNEL_AFDO_VERIFIER_BOARDS.values()
-  ] + ['chromeos-chrome']
-  if package not in valid_package_names:
-    raise ValueError('Invalid package name %s to look up ebuild.' % package)
-
-  if board:
-    equery_prog = 'equery-%s' % board
-  else:
-    equery_prog = 'equery'
-  equery_cmd = [equery_prog, 'w', package]
-  ebuild_file = cros_build_lib.run(
-      equery_cmd, enter_chroot=True, stdout=True,
-      encoding='utf-8').output.rstrip()
-  if not buildroot:
-    return ebuild_file
-
-  basepath = '/mnt/host/source'
-  if not ebuild_file.startswith(basepath):
-    raise ValueError('Unexpected ebuild path: %s' % ebuild_file)
-  ebuild_path = os.path.relpath(ebuild_file, basepath)
-  return os.path.join(buildroot, ebuild_path)
-
-
 def _GetArtifactVersionInChromium(arch, chrome_root):
   """Find the version (name) of AFDO artifact from chromium source.
 
@@ -374,34 +310,6 @@
   return osutils.ReadFile(profile_file)
 
 
-def _GetArtifactVersionInEbuild(package, variable, buildroot=None):
-  """Find the version (name) of AFDO artifact from files in ebuild.
-
-  Args:
-    package: The name of the package to search in ebuild.
-    variable: Use this variable directly as regex to search.
-    buildroot: Optional. When omitted, search ebuild file inside
-    chroot. Otherwise, use the path to search ebuild file outside.
-
-  Returns:
-    The name of the AFDO artifact found in the ebuild.
-    None if not found.
-  """
-  ebuild_file = _FindEbuildPath(package, buildroot=buildroot)
-  pattern = re.compile(AFDO_ARTIFACT_EBUILD_REGEX % variable)
-  with open(ebuild_file) as f:
-    for line in f:
-      matched = pattern.match(line)
-      if matched:
-        ret = matched.group('name')
-        if ret.startswith('"') and ret.endswith('"'):
-          return ret[1:-1]
-        return ret
-
-  logging.info('%s is not found in the ebuild: %s', variable, ebuild_file)
-  return None
-
-
 def _GetCombinedAFDOName(cwp_versions, cwp_arch, benchmark_versions):
   """Construct a name mixing CWP and benchmark AFDO names.
 
@@ -448,36 +356,6 @@
       _GetCombinedAFDOName(cwp_afdo_version, 'field', benchmark_afdo_version))
 
 
-def _GetBenchmarkAFDOName(buildroot, board):
-  """Constructs a benchmark AFDO name for the current build root.
-
-  Args:
-    buildroot: The path to build root.
-    board: The name of the board.
-
-  Returns:
-    A string similar to: chromeos-chrome-amd64-77.0.3849.0_rc-r1.afdo
-  """
-  pkg_info = portage_util.PortageqBestVisible(
-      constants.CHROME_CP, cwd=buildroot)
-  arch = portage_util.PortageqEnvvar('ARCH', board=board, allow_undefined=True)
-  afdo_spec = {
-      'package': pkg_info.package,
-      'arch': arch,
-      'version': pkg_info.vr,
-  }
-  afdo_file = CHROME_BENCHMARK_AFDO_FILE % afdo_spec
-  try:
-    _ParseBenchmarkProfileName(afdo_file)
-  except ProfilesNameHelperError:
-    # We want to avoid uploading a profile with an unparsable name. There's no
-    # reason to upload a profile with unparsable name because no builds can
-    # use it anyway. See crbug.com/1048725 for such instances.
-    raise ValueError('Invalid to use %s as AFDO name because of unparsable' %
-                     afdo_file)
-  return afdo_file
-
-
 def _CompressAFDOFiles(targets, input_dir, output_dir, suffix):
   """Compress files using AFDO compression type.
 
@@ -506,157 +384,15 @@
       raise RuntimeError('file %s to compress does not exist' % input_path)
     output_path = os.path.join(output_dir, compressed)
     cros_build_lib.CompressFile(input_path, output_path)
+    logging.info('_CompressAFDOFiles produced %s, size %.1fMB',
+                 output_path, os.path.getsize(output_path) / (1024 * 1024))
     ret.append(output_path)
   return ret
 
 
-def _UploadAFDOArtifactToGSBucket(gs_url, local_path, rename=''):
-  """Upload AFDO artifact to a centralized GS Bucket.
-
-  Args:
-    gs_url: The location to upload the artifact.
-    local_path: Full local path to the file.
-    rename: Optional. The name used in the bucket. If omitted, will use
-    the same name as in local path.
-
-  Raises:
-    RuntimeError if the file to upload doesn't exist.
-  """
-  gs_context = gs.GSContext()
-
-  if not os.path.exists(local_path):
-    raise RuntimeError('file %s to upload does not exist' % local_path)
-
-  if rename:
-    remote_name = rename
-  else:
-    remote_name = os.path.basename(local_path)
-  url = os.path.join(gs_url, remote_name)
-
-  if gs_context.Exists(url):
-    logging.info('URL %s already exists, skipping uploading...', url)
-    return
-
-  gs_context.Copy(local_path, url, acl='public-read')
-
-
-def _MergeAFDOProfiles(chroot_profile_list,
-                       chroot_output_profile,
-                       use_compbinary=False):
-  """Merges the given profile list.
-
-  This function is copied over from afdo.py.
-
-  Args:
-    chroot_profile_list: a list of (profile_path, profile_weight).
-      Profile_weight is an int that tells us how to weight the profile compared
-      to everything else.
-    chroot_output_profile: where to store the result profile.
-    use_compbinary: whether to use the new compressed binary AFDO profile
-      format.
-  """
-  if not chroot_profile_list:
-    raise ValueError('Need profiles to merge')
-
-  # A regular llvm-profdata command looks like:
-  # llvm-profdata merge [-sample] -output=/path/to/output input1 [input2
-  #                                                               [input3 ...]]
-  #
-  # Alternatively, we can specify inputs by `-weighted-input=A,file`, where A
-  # is a multiplier of the sample counts in the profile.
-  merge_command = [
-      'llvm-profdata',
-      'merge',
-      '-sample',
-      '-output=' + chroot_output_profile,
-  ]
-
-  merge_command += [
-      '-weighted-input=%d,%s' % (weight, name)
-      for name, weight in chroot_profile_list
-  ]
-
-  if use_compbinary:
-    merge_command.append('-compbinary')
-
-  cros_build_lib.run(merge_command, enter_chroot=True, print_cmd=True)
-
-
-def _RedactAFDOProfile(input_path, output_path):
-  """Redact ICF'ed symbols and indirect calls from AFDO profiles.
-
-  ICF can cause inflation on AFDO sampling results, so we want to remove
-  them from AFDO profiles used for Chrome.
-  See http://crbug.com/916024 for more details.
-
-  Indirect calls can cause the size increase of nacl, so we need to remove them
-  from AFDO profiles.
-  See http://crbug.com/1057153 for more details.
-
-  Args:
-    input_path: Full path to input AFDO profile.
-    output_path: Full path to output AFDO profile.
-  """
-
-  profdata_command_base = ['llvm-profdata', 'merge', '-sample']
-  # Convert the compbinary profiles to text profiles.
-  input_to_text_temp = input_path + '.text.temp'
-  convert_to_text_command = profdata_command_base + [
-      '-text', input_path, '-output', input_to_text_temp
-  ]
-  cros_build_lib.run(convert_to_text_command, enter_chroot=True, print_cmd=True)
-
-  # Call the redaction script.
-  redacted_temp = input_path + '.redacted.temp'
-  with open(input_to_text_temp, 'rb') as f:
-    cros_build_lib.run(
-        ['redact_textual_afdo_profile'],
-        input=f,
-        stdout=redacted_temp,
-        enter_chroot=True,
-        print_cmd=True,
-    )
-
-  # Call the remove indirect call script
-  removed_temp = input_path + '.removed.temp'
-  cros_build_lib.run(
-      [
-          'remove_indirect_calls',
-          '--input=' + redacted_temp,
-          '--output=' + removed_temp,
-      ],
-      enter_chroot=True,
-      print_cmd=True,
-  )
-
-  # Remove cold functions in the profile. Trim the profile to contain 20k
-  # functions, as our current profile has ~20k functions so this modification
-  # brings less impact on prod.
-  reduced_temp = input_path + '.reduced.temp'
-  cros_build_lib.run(
-      [
-          'remove_cold_functions',
-          '--input=' + removed_temp,
-          '--output=' + reduced_temp,
-          '--number=20000',
-      ],
-      enter_chroot=True,
-      print_cmd=True,
-  )
-
-  # Convert the profiles back to compbinary profiles.
-  # Using `compbinary` profiles saves us hundreds of MB of RAM per
-  # compilation, since it allows profiles to be lazily loaded.
-  convert_to_combinary_command = profdata_command_base + [
-      '-compbinary',
-      reduced_temp,
-      '-output',
-      output_path,
-  ]
-  cros_build_lib.run(
-      convert_to_combinary_command, enter_chroot=True, print_cmd=True)
-
-
+# TODO(b/187794927): Refactor the class.
+# The class was shared with the legacy builders. Legacy was removed and
+# now we can merge this code into the BundleArtifactHandler class.
 class GenerateChromeOrderfile(object):
   """Class to handle generation of orderfile for Chrome.
 
@@ -777,122 +513,6 @@
     self.tarballs = _CompressAFDOFiles([chrome_nm, orderfile], self.working_dir,
                                        self.output_dir, XZ_COMPRESSION_SUFFIX)
 
-  def Perform(self):
-    """Generate post-processed Chrome orderfile and create tarball."""
-    self.Bundle()
-    for t in self.tarballs:
-      _UploadAFDOArtifactToGSBucket(ORDERFILE_GS_URL_UNVETTED, t)
-
-
-class UpdateEbuildWithAFDOArtifacts(object):
-  """Class to update ebuild with unvetted AFDO artifacts.
-
-  This class is used to verify an unvetted AFDO artifact, by patching
-  the ebuild of the package with a dictionary of rules.
-
-  This class runs inside chroot, so all the paths should be relative
-  inside chroot.
-  """
-
-  def __init__(self, board, package, update_rules):
-    """Construct an object for updating ebuild with AFDO artifacts.
-
-    Args:
-      board: Name of the board.
-      package: Name of the package to test with.
-      update_rules: A dict containing pairs of (key, value) used to
-      patch ebuild. "key" will be used to search ebuild as an variable,
-      and update that variable with "value".
-    """
-    self.board = board
-    self.package = package
-    self.update_rules = update_rules
-
-  def _PatchEbuild(self, ebuild_file):
-    """Patch the specified ebuild to use the artifact.
-
-    Args:
-      ebuild_file: path to the ebuild file.
-
-    Raises:
-      UpdateEbuildWithAFDOArtifactsError: If marker is not found.
-    """
-    original_ebuild = path_util.FromChrootPath(ebuild_file)
-    modified_ebuild = '%s.new' % original_ebuild
-
-    patterns = []
-    replacements = []
-    for name, value in self.update_rules.items():
-      patterns.append(re.compile(AFDO_ARTIFACT_EBUILD_REGEX % name))
-      replacements.append(AFDO_ARTIFACT_EBUILD_REPL % value)
-
-    found = set()
-    with open(original_ebuild) as original, \
-         open(modified_ebuild, 'w') as modified:
-      for line in original:
-        matched = False
-        for p, r in zip(patterns, replacements):
-          matched = p.match(line)
-          if matched:
-            found.add(r)
-            modified.write(p.sub(r, line))
-            # Each line can only match one pattern
-            break
-        if not matched:
-          modified.write(line)
-    not_updated = set(replacements) - found
-    if not_updated:
-      logging.info('Unable to update %s in the ebuild', not_updated)
-      raise UpdateEbuildWithAFDOArtifactsError(
-          'Ebuild file does not have appropriate marker for AFDO/orderfile.')
-
-    os.rename(modified_ebuild, original_ebuild)
-    for name, value in self.update_rules.items():
-      logging.info('Patched %s with (%s, %s)', original_ebuild, name, value)
-
-  def _UpdateManifest(self, ebuild_file):
-    """Regenerate the Manifest file. (To update orderfile)
-
-    Args:
-      ebuild_file: path to the ebuild file
-    """
-    ebuild_prog = 'ebuild-%s' % self.board
-    cmd = [ebuild_prog, ebuild_file, 'manifest', '--force']
-    cros_build_lib.run(cmd, enter_chroot=True)
-
-  def Perform(self):
-    """Main function to update ebuild with the rules."""
-    ebuild = _FindEbuildPath(self.package, board=self.board)
-    self._PatchEbuild(ebuild)
-    # Patch the chrome 9999 ebuild too, as the manifest will use
-    # 9999 ebuild.
-    ebuild_9999 = os.path.join(
-        os.path.dirname(ebuild), self.package + '-9999.ebuild')
-    self._PatchEbuild(ebuild_9999)
-    # Use 9999 ebuild to update manifest.
-    self._UpdateManifest(ebuild_9999)
-
-
-def _RankValidBenchmarkProfiles(name):
-  """Calculate a value used to rank valid benchmark profiles.
-
-  Args:
-    name: A name or a full path of a possible benchmark profile.
-
-  Returns:
-    A BenchmarkProfileNamedTuple used for ranking if the name
-    is a valid benchmark profile. Otherwise, returns None.
-  """
-  try:
-    version = _ParseBenchmarkProfileName(os.path.basename(name))
-    # Filter out merged benchmark profiles.
-    if version.is_merged:
-      return None
-    return version
-  except ProfilesNameHelperError:
-    return None
-
-
 def _RankValidCWPProfiles(name):
   """Calculate a value used to rank valid CWP profiles.
 
@@ -909,105 +529,6 @@
     return None
 
 
-def _RankValidOrderfiles(name):
-  """Calculcate a value used to rank valid orderfiles.
-
-  Args:
-    name: A name or a full path of a possible orderfile.
-
-  Returns:
-    A tuple of (BenchmarkProfileNamedTuple, "clock" part of CWP profile),
-    or returns None if the name is not a valid orderfile name.
-
-  Raises:
-    ValueError, if the parsed orderfile is not valid.
-  """
-  try:
-    benchmark_part, cwp_part = _ParseMergedProfileName(os.path.basename(name))
-    if benchmark_part.is_merged:
-      raise ValueError(
-          '-merged should not appear in orderfile or release AFDO name.')
-    return benchmark_part, cwp_part.clock
-  except ProfilesNameHelperError:
-    return None
-
-
-def _FindLatestAFDOArtifact(gs_url, ranking_function):
-  """Find the latest AFDO artifact in a GS bucket.
-
-  Always finds profiles that matches the current Chrome branch.
-
-  Args:
-    gs_url: The full path to GS bucket URL.
-    ranking_function: A function used to evaluate a full url path.
-    e.g. foo(x) should return a value that can use to rank the profile,
-    or return None if the url x is not relevant.
-
-  Returns:
-    The name of the eligible latest AFDO artifact.
-
-  Raises:
-    RuntimeError: If no files matches the regex in the bucket.
-    ValueError: if regex is not valid.
-  """
-
-  def _FilterResultsBasedOnBranch(branch):
-    """Filter out results that doesn't belong to this branch."""
-    # The branch should appear in the name either as:
-    # R78-12371.22-1566207135 for kernel/CWP profiles
-    # OR chromeos-chrome-amd64-78.0.3877.0 for benchmark profiles
-    return [
-        x for x in all_files
-        if 'R%s' % branch in x.url or '-%s.' % branch in x.url
-    ]
-
-  gs_context = gs.GSContext()
-
-  # Obtain all files from gs_url and filter out those not match
-  # pattern. And filter out text files for legacy PFQ like
-  # latest-chromeos-chrome-amd64-79.afdo
-  all_files = [
-      x for x in gs_context.List(gs_url, details=True) if 'latest-' not in x.url
-  ]
-  chrome_branch = _FindCurrentChromeBranch()
-  results = _FilterResultsBasedOnBranch(chrome_branch)
-
-  if not results:
-    # If no results found, it's maybe because we just branched.
-    # Try to find the latest profile from last branch.
-    results = _FilterResultsBasedOnBranch(str(int(chrome_branch) - 1))
-    if not results:
-      raise RuntimeError('No files found on %s for branch %s' %
-                         (gs_url, chrome_branch))
-
-  ranked_results = [(ranking_function(x.url), x.url) for x in results]
-  filtered_results = [x for x in ranked_results if x[0] is not None]
-  if not filtered_results:
-    raise RuntimeError('No valid latest artifact was found on %s'
-                       '(example invalid artifact: %s).' %
-                       (gs_url, results[0].url))
-
-  latest = max(filtered_results)
-  name = os.path.basename(latest[1])
-  logging.info('Latest AFDO artifact in %s is %s', gs_url, name)
-  return name
-
-
-def _FindCurrentChromeBranch():
-  """Find the current Chrome branch from Chrome ebuild.
-
-  Returns:
-    The branch version as a str.
-  """
-  chrome_ebuild = os.path.basename(_FindEbuildPath('chromeos-chrome'))
-  pattern = re.compile(
-      r'chromeos-chrome-(?P<branch>\d+)\.\d+\.\d+\.\d+(?:_rc)?-r\d+.ebuild')
-  match = pattern.match(chrome_ebuild)
-  if not match:
-    raise ValueError('Unparseable chrome ebuild name: %s' % chrome_ebuild)
-
-  return match.group('branch')
-
 
 def _GetProfileAge(profile, artifact_type):
   """Tell the age of profile_version in days.
@@ -1033,8 +554,8 @@
   raise ValueError('Only kernel afdo is supported to check profile age.')
 
 
-def _WarnSheriffAboutKernelProfileExpiration(kver, profile):
-  """Send emails to toolchain sheriff to warn the soon expired profiles.
+def _WarnDetectiveAboutKernelProfileExpiration(kver, profile):
+  """Send emails to toolchain detective to warn the soon expired profiles.
 
   Args:
     kver: Kernel version.
@@ -1069,8 +590,7 @@
     self.chroot = chroot
     self.sysroot_path = sysroot_path
     self.build_target = build_target
-    # TODO(crbug/1019868): revisit when arch != amd64 becomes something we care
-    # about.
+    # TODO(b/204477388): This should be modified in the Arm pipeline.
     self.arch = 'amd64'
     self.input_artifacts = input_artifacts or {}
     self.profile_info = profile_info or {}
@@ -1198,7 +718,7 @@
     pattern = re.compile(AFDO_ARTIFACT_EBUILD_REGEX % variable)
     with open(ebuild) as f:
       for line in f:
-        match = pattern.match(line)
+        match = pattern.search(line)
         if match:
           ret = match.group('name')
           if ret.startswith('"') and ret.endswith('"'):
@@ -1335,21 +855,6 @@
         return path
     return None
 
-  def _UpdateEbuildWithArtifacts(self, package, update_rules):
-    """Update a package ebuild file with artifacts.
-
-    Args:
-      package: name of package to update (no category.)
-      update_rules: dict{'variable': 'value'} to apply.
-    """
-    info = self._GetEbuildInfo(package)
-    self._PatchEbuild(info, update_rules, uprev=True)
-    package_9999 = info.CPV.with_version('9999')
-    ebuild_9999 = os.path.join(
-        os.path.dirname(info.path), package_9999.ebuild)
-    info_9999 = _EbuildInfo(ebuild_9999, package_9999)
-    self._PatchEbuild(info_9999, update_rules, uprev=False)
-
   def _PatchEbuild(self, info, rules, uprev):
     """Patch an ebuild file, possibly uprevving it.
 
@@ -1447,22 +952,6 @@
     except ProfilesNameHelperError:
       return None
 
-  @staticmethod
-  def _RankValidCWPProfiles(name):
-    """Calculate a value used to rank valid benchmark profiles.
-
-    Args:
-      name: A name or a full path of a possible benchmark profile.
-
-    Returns:
-      A BenchmarkProfileNamedTuple used for ranking if the name
-      is a valid benchmark profile. Otherwise, returns None.
-    """
-    try:
-      return _ParseCWPProfileName(os.path.basename(name)).clock
-    except ProfilesNameHelperError:
-      return None
-
   def _CreateReleaseChromeAFDO(self, cwp_url, bench_url, output_dir,
                                merged_name):
     """Create an AFDO profile to be used in release Chrome.
@@ -1578,6 +1067,9 @@
       reduce_functions: Remove the cold functions in the profile until the
         given number is met.
       compbinary: Whether to convert the final profile into compbinary type.
+
+    Raises:
+      BundleArtifactsHandlerError: If the output profile is empty.
     """
     profdata_command_base = ['llvm-profdata', 'merge', '-sample']
     # Convert the compbinary profiles to text profiles.
@@ -1644,6 +1136,17 @@
       cmd_to_binary.append('-compbinary')
     cros_build_lib.run(cmd_to_binary, enter_chroot=True, print_cmd=True)
 
+    profile_size = os.path.getsize(output_path)
+    logging.info('_ProcessAFDOProfile produced AFDO profile %s, size %.1fMB',
+                 output_path, profile_size / (1024 * 1024))
+    # Verify the profile size.
+    # Empty profiles in a binary format can have a non-zero size
+    # because of the header but they won't exceed the page size.
+    # Normal profiles are usually >1MB.
+    if profile_size < 4096:
+      raise BundleArtifactsHandlerError(
+          f'_ProcessAFDOProfile produced empty AFDO profile, {profile_size}')
+
   def _CreateAndUploadMergedAFDOProfile(self,
                                         unmerged_profile,
                                         output_dir,
@@ -1990,7 +1493,7 @@
             [os.path.join(KERNEL_PROFILE_URL, kernel_version)])
     ]
     afdo_path = self._FindLatestAFDOArtifact(cwp_locs,
-                                             self._RankValidCWPProfiles)
+                                             _RankValidCWPProfiles)
 
     published_path = os.path.join(
         self.input_artifacts.get(
@@ -2016,7 +1519,7 @@
       ret = PrepareForBuildReturn.POINTLESS
 
     if age > KERNEL_WARN_STALE_DAYS:
-      _WarnSheriffAboutKernelProfileExpiration(kernel_version, afdo_name)
+      _WarnDetectiveAboutKernelProfileExpiration(kernel_version, afdo_name)
 
     # If we don't have an SDK, then we cannot update the manifest.
     if self.chroot:
@@ -2056,7 +1559,7 @@
     # This will raise a RuntimeError if no artifact is found.
     bench = self._FindLatestAFDOArtifact(bench_locs,
                                          self._RankValidBenchmarkProfiles)
-    cwp = self._FindLatestAFDOArtifact(cwp_locs, self._RankValidCWPProfiles)
+    cwp = self._FindLatestAFDOArtifact(cwp_locs, _RankValidCWPProfiles)
     bench_name = os.path.split(bench)[1]
     cwp_name = os.path.split(cwp)[1]
 
@@ -2147,7 +1650,12 @@
   def _BundleVerifiedChromeLlvmOrderfile(self):
     """Bundle vetted ordering file."""
     orderfile_name = self._GetArtifactVersionInEbuild(
-        constants.CHROME_PN, 'UNVETTED_ORDERFILE') + XZ_COMPRESSION_SUFFIX
+        constants.CHROME_PN, 'UNVETTED_ORDERFILE')
+    if not orderfile_name:
+      raise BundleArtifactsHandlerError(
+          f'Could not find UNVETTED_ORDERFILE version in {constants.CHROME_PN}')
+    orderfile_name += XZ_COMPRESSION_SUFFIX
+
     # Strip the leading / from sysroot_path.
     orderfile_path = self.chroot.full_path(self.sysroot_path,
                                            'opt/google/chrome', orderfile_name)
@@ -2272,6 +1780,11 @@
     return [bin_path]
 
   def _BundleUnverifiedChromeBenchmarkAfdoFile(self):
+    """Bundle a benchmark Chrome AFDO profile.
+
+    Raises:
+      BundleArtifactsHandlerError: If the output profile is empty.
+    """
     files = []
     # If the name of the provided binary is not 'chrome.unstripped', then
     # create_llvm_prof demands it exactly matches the name of the unstripped
@@ -2298,7 +1811,16 @@
         ],
         enter_chroot=True,
         print_cmd=True)
-    logging.info('Generated %s AFDO profile %s', self.arch, afdo_name)
+    profile_size = os.path.getsize(self.chroot.full_path(afdo_path_inside))
+    # Check if the profile is empty.
+    # Empty profiles in a binary format can have a non-zero size
+    # because of the header but they won't exceed the page size.
+    # Normal profiles are usually >1MB.
+    if profile_size < 4096:
+      raise BundleArtifactsHandlerError(
+          f'AFDO profile size has invalid size, {profile_size}')
+    logging.info('Generated %s AFDO profile %s, size %.1fMB',
+                 self.arch, afdo_name, profile_size / (1024 * 1024))
 
     # Compress and deliver the profile.
     afdo_path = os.path.join(self.output_dir,
@@ -2358,8 +1880,12 @@
       raise BundleArtifactsHandlerError('kernel_version not provided.')
     kernel_version = kernel_version.replace('.', '_')
     profile_name = self._GetArtifactVersionInEbuild(
-        'chromeos-kernel-%s' % kernel_version,
-        'AFDO_PROFILE_VERSION') + KERNEL_AFDO_COMPRESSION_SUFFIX
+        f'chromeos-kernel-{kernel_version}', 'AFDO_PROFILE_VERSION')
+    if not profile_name:
+      raise BundleArtifactsHandlerError(
+          'Could not find AFDO_PROFILE_VERSION in '
+          f'chromeos-kernel-{kernel_version}.')
+    profile_name += KERNEL_AFDO_COMPRESSION_SUFFIX
     # The verified profile is in the sysroot with a name similar to:
     # /usr/lib/debug/boot/chromeos-kernel-4_4-R82-12874.0-1581935639.gcov.xz
     profile_path = os.path.join(
@@ -2633,686 +2159,3 @@
 def GetUpdatedFiles(artifact_type, artifact_path, profile_info):
   return GetUpdatedFilesHandler(artifact_type, artifact_path,
                                 profile_info).Update()
-
-
-# ###########################################################################
-#
-# TODO(crbug/1019868): delete once cbuildbot is gone.
-# LEGACY CODE: used primarily by cbuildbot.
-#
-# ###########################################################################
-def OrderfileUpdateChromeEbuild(board):
-  """Update Chrome ebuild with latest unvetted orderfile.
-
-  Args:
-    board: Board type that was built on this machine.
-
-  Returns:
-    Status of the update.
-  """
-
-  orderfile_name = _FindLatestAFDOArtifact(ORDERFILE_GS_URL_UNVETTED,
-                                           _RankValidOrderfiles)
-
-  if not orderfile_name:
-    logging.info('No eligible orderfile to verify.')
-    return False
-
-  updater = UpdateEbuildWithAFDOArtifacts(
-      board=board,
-      package='chromeos-chrome',
-      update_rules={'UNVETTED_ORDERFILE': os.path.splitext(orderfile_name)[0]})
-  updater.Perform()
-  return True
-
-
-def AFDOUpdateChromeEbuild(board):
-  """Update Chrome ebuild with latest unvetted AFDO profiles.
-
-  Args:
-    board: Board to verify the Chrome afdo.
-
-  Returns:
-    Status of the update.
-  """
-  benchmark_afdo = _FindLatestAFDOArtifact(BENCHMARK_AFDO_GS_URL,
-                                           _RankValidBenchmarkProfiles)
-  arch = CHROME_AFDO_VERIFIER_BOARDS[board]
-  url = os.path.join(CWP_AFDO_GS_URL, arch)
-  cwp_afdo = _FindLatestAFDOArtifact(url, _RankValidCWPProfiles)
-
-  if not benchmark_afdo or not cwp_afdo:
-    logging.info('No eligible benchmark or cwp AFDO to verify.')
-    return False
-
-  with osutils.TempDir() as tempdir:
-    result = _CreateReleaseChromeAFDO(
-        os.path.splitext(cwp_afdo)[0], arch,
-        os.path.splitext(benchmark_afdo)[0], tempdir)
-    afdo_profile_for_verify = os.path.join('/tmp', os.path.basename(result))
-    os.rename(result, afdo_profile_for_verify)
-
-  updater = UpdateEbuildWithAFDOArtifacts(
-      board=board,
-      package='chromeos-chrome',
-      update_rules={'UNVETTED_AFDO_FILE': afdo_profile_for_verify})
-  updater.Perform()
-  return True
-
-
-def AFDOUpdateKernelEbuild(board):
-  """Update kernel ebuild with latest unvetted AFDO profile.
-
-  Args:
-    board: Board to verify the kernel type.
-
-  Returns:
-    Status of the update.
-  """
-
-  # For kernel profiles, need to find out the current branch in order to
-  # filter out profiles on other branches.
-  url = os.path.join(KERNEL_PROFILE_URL, KERNEL_AFDO_VERIFIER_BOARDS[board])
-  kernel_afdo = _FindLatestAFDOArtifact(url, _RankValidCWPProfiles)
-  kver = KERNEL_AFDO_VERIFIER_BOARDS[board].replace('.', '_')
-  # The kernel_afdo from GS bucket contains .gcov.xz suffix, but the name
-  # of the afdo in kernel ebuild doesn't. Need to strip it out.
-  kernel_afdo_in_ebuild = kernel_afdo.replace(KERNEL_AFDO_COMPRESSION_SUFFIX,
-                                              '')
-
-  # Check freshness
-  age = _GetProfileAge(kernel_afdo_in_ebuild, 'kernel_afdo')
-  if age > KERNEL_ALLOWED_STALE_DAYS:
-    logging.info('Found an expired afdo for kernel %s: %s, skip.', kver,
-                 kernel_afdo_in_ebuild)
-    return False
-
-  if age > KERNEL_WARN_STALE_DAYS:
-    _WarnSheriffAboutKernelProfileExpiration(kver, kernel_afdo_in_ebuild)
-
-  updater = UpdateEbuildWithAFDOArtifacts(
-      board=board,
-      package='chromeos-kernel-' + kver,
-      update_rules={'AFDO_PROFILE_VERSION': kernel_afdo_in_ebuild})
-  updater.Perform()
-  return True
-
-
-class GenerateBenchmarkAFDOProfile(object):
-  """Class that generate benchmark AFDO profile.
-
-  This class waits for the raw sampled profile data (perf.data) from another
-  stage that runs hardware tests and uploads it to GS bucket. Once the profile
-  is seen, this class downloads the raw profile, and processes it into
-  LLVM-readable AFDO profiles. Then uploads the AFDO profile. This class also
-  uploads an unstripped Chrome binary for debugging purpose if needed.
-  """
-
-  def __init__(self, board, output_dir, chroot_path, chroot_args):
-    """Construct an object for generating benchmark profiles.
-
-    Args:
-      board: The name of the board.
-      output_dir: The path to save output files.
-      chroot_path: The chroot path.
-      chroot_args: The arguments used to enter chroot.
-    """
-    self.board = board
-    self.chroot_path = chroot_path
-    self.chroot_args = chroot_args
-    self.buildroot = os.path.join(chroot_path, '..')
-    self.chrome_pkg = portage_util.PortageqBestVisible(
-        constants.CHROME_CP, cwd=self.buildroot)
-    self.arch = portage_util.PortageqEnvvar(
-        'ARCH', board=board, allow_undefined=True)
-    # Directory used to store intermediate artifacts
-    self.working_dir = os.path.join(self.chroot_path, 'tmp')
-    self.working_dir_inchroot = '/tmp'
-    # Output directory
-    self.output_dir = output_dir
-
-  def _DecompressAFDOFile(self, to_decompress):
-    """Decompress file used by AFDO process.
-
-    Args:
-      to_decompress: File to decompress.
-
-    Returns:
-      The full path to the uncompressed file.
-    """
-    basename = os.path.basename(to_decompress)
-    dest_basename = os.path.splitext(basename)[0]
-    dest = os.path.join(self.working_dir, dest_basename)
-    cros_build_lib.UncompressFile(to_decompress, dest)
-    return dest
-
-  def _GetPerfAFDOName(self):
-    """Construct a name for perf.data for current chrome version."""
-    # The file name of the perf data is based only in the chrome version.
-    # The test case that produces it does not know anything about the
-    # revision number.
-    # TODO(llozano): perf data filename should include the revision number.
-    version_number = self.chrome_pkg.version.split('_')[0]
-    chrome_spec = {
-        'package': self.chrome_pkg.package,
-        'arch': self.arch,
-        'versionnorev': version_number
-    }
-    return CHROME_PERF_AFDO_FILE % chrome_spec
-
-  def _CheckAFDOPerfDataStatus(self):
-    """Check whether AFDO perf data on GS bucket.
-
-    Check if 'perf' data file for this architecture and release is available
-    in GS.
-
-    Returns:
-      True if AFDO perf data is available. False otherwise.
-    """
-    gs_context = gs.GSContext()
-    url = os.path.join(BENCHMARK_AFDO_GS_URL,
-                       self._GetPerfAFDOName() + BZ2_COMPRESSION_SUFFIX)
-    if not gs_context.Exists(url):
-      logging.info('Could not find AFDO perf data at %s', url)
-      return False
-
-    logging.info('Found AFDO perf data at %s', url)
-    return True
-
-  def _WaitForAFDOPerfData(self):
-    """Wait until hwtest finishes and the perf.data uploaded to GS bucket.
-
-    Returns:
-      True if hwtest finishes and perf.data is copied to local buildroot
-      False if timeout.
-    """
-    try:
-      timeout_util.WaitForReturnTrue(
-          self._CheckAFDOPerfDataStatus,
-          timeout=constants.AFDO_GENERATE_TIMEOUT,
-          period=constants.SLEEP_TIMEOUT)
-    except timeout_util.TimeoutError:
-      logging.info('Could not find AFDO perf data before timeout')
-      return False
-
-    gs_context = gs.GSContext()
-    url = os.path.join(BENCHMARK_AFDO_GS_URL,
-                       self._GetPerfAFDOName() + BZ2_COMPRESSION_SUFFIX)
-    dest_path = os.path.join(self.working_dir, url.rsplit('/', 1)[1])
-    gs_context.Copy(url, dest_path)
-
-    self._DecompressAFDOFile(dest_path)
-    logging.info('Retrieved AFDO perf data to %s', dest_path)
-    return True
-
-  def _CreateAFDOFromPerfData(self):
-    """Create LLVM-readable AFDO profile from raw sampled perf data.
-
-    Returns:
-      Name of the generated AFDO profile.
-    """
-    CHROME_UNSTRIPPED_NAME = 'chrome.unstripped'
-    # create_llvm_prof demands the name of the profiled binary exactly matches
-    # the name of the unstripped binary or it is named 'chrome.unstripped'.
-    # So create a symbolic link with the appropriate name.
-    debug_sym = os.path.join(self.working_dir, CHROME_UNSTRIPPED_NAME)
-    debug_binary_inchroot = _CHROME_DEBUG_BIN % {
-        'root': '',
-        'sysroot': os.path.join('build', self.board)
-    }
-    osutils.SafeSymlink(debug_binary_inchroot, debug_sym)
-
-    # Call create_llvm_prof tool to generated AFDO profile from 'perf' profile
-    # These following paths are converted to the path relative inside chroot.
-    debug_sym_inchroot = os.path.join(self.working_dir_inchroot,
-                                      CHROME_UNSTRIPPED_NAME)
-    perf_afdo_inchroot_path = os.path.join(self.working_dir_inchroot,
-                                           self._GetPerfAFDOName())
-    afdo_name = _GetBenchmarkAFDOName(self.buildroot, self.board)
-    afdo_inchroot_path = os.path.join(self.working_dir_inchroot, afdo_name)
-    afdo_cmd = [
-        _AFDO_GENERATE_LLVM_PROF,
-        '--binary=%s' % debug_sym_inchroot,
-        '--profile=%s' % perf_afdo_inchroot_path,
-        '--out=%s' % afdo_inchroot_path,
-    ]
-    cros_build_lib.run(
-        afdo_cmd,
-        enter_chroot=True,
-        capture_output=True,
-        print_cmd=True,
-        chroot_args=self.chroot_args)
-
-    logging.info('Generated %s AFDO profile %s', self.arch, afdo_name)
-    return afdo_name
-
-  def _UploadArtifacts(self, debug_bin, afdo_name):
-    """Upload Chrome debug binary and AFDO profile with version info.
-
-    Args:
-      debug_bin: The name of debug Chrome binary.
-      afdo_name: The name of AFDO profile.
-    """
-
-    afdo_spec = {
-        'package': self.chrome_pkg.package,
-        'arch': self.arch,
-        'version': self.chrome_pkg.vr
-    }
-    debug_bin_full_path = os.path.join(
-        self.output_dir,
-        os.path.basename(debug_bin) + BZ2_COMPRESSION_SUFFIX)
-    chrome_version = CHROME_ARCH_VERSION % afdo_spec
-    debug_bin_name_with_version = (
-        chrome_version + '.debug' + BZ2_COMPRESSION_SUFFIX)
-
-    # Upload Chrome debug binary and rename it
-    _UploadAFDOArtifactToGSBucket(
-        BENCHMARK_AFDO_GS_URL,
-        debug_bin_full_path,
-        rename=debug_bin_name_with_version)
-
-    # Upload Benchmark AFDO profile as is
-    _UploadAFDOArtifactToGSBucket(
-        BENCHMARK_AFDO_GS_URL,
-        os.path.join(self.output_dir, afdo_name + BZ2_COMPRESSION_SUFFIX))
-
-  def _GenerateAFDOData(self):
-    """Generate AFDO profile data from 'perf' data.
-
-    Given the 'perf' profile, generate an AFDO profile using
-    create_llvm_prof. It also compresses Chrome debug binary to upload.
-
-    Returns:
-      The name created AFDO artifact.
-    """
-    debug_bin = _CHROME_DEBUG_BIN % {
-        'root': self.chroot_path,
-        'sysroot': os.path.join('build', self.board)
-    }
-    afdo_name = self._CreateAFDOFromPerfData()
-
-    # Because debug_bin and afdo file are in different paths, call the compress
-    # function separately.
-    _CompressAFDOFiles(
-        targets=[debug_bin],
-        input_dir=None,
-        output_dir=self.output_dir,
-        suffix=BZ2_COMPRESSION_SUFFIX)
-
-    _CompressAFDOFiles(
-        targets=[afdo_name],
-        input_dir=self.working_dir,
-        output_dir=self.output_dir,
-        suffix=BZ2_COMPRESSION_SUFFIX)
-
-    self._UploadArtifacts(debug_bin, afdo_name)
-    return afdo_name
-
-  def Perform(self):
-    """Main function to generate benchmark AFDO profiles.
-
-    Raises:
-      GenerateBenchmarkAFDOProfilesError, if it never finds a perf.data
-      file uploaded to GS bucket.
-    """
-    if self._WaitForAFDOPerfData():
-      afdo_file = self._GenerateAFDOData()
-      # FIXME(tcwang): reuse the CreateAndUploadMergedAFDOProfile from afdo.py
-      # as a temporary solution to keep Android/Linux AFDO running.
-      # Need to move the logic to this file, and run it either at generating
-      # benchmark profiles, or at verifying Chrome profiles.
-      gs_context = gs.GSContext()
-      afdo.CreateAndUploadMergedAFDOProfile(gs_context, self.buildroot,
-                                            afdo_file)
-    else:
-      raise GenerateBenchmarkAFDOProfilesError(
-          'Could not find current "perf" profile.')
-
-
-def CanGenerateAFDOData(board):
-  """Does this board has the capability of generating its own AFDO data?"""
-  return board in AFDO_DATA_GENERATORS_LLVM
-
-
-def CanVerifyKernelAFDOData(board):
-  """Does the board eligible to verify kernel AFDO profile.
-
-  We use the name of the board to find the kernel version, so we only
-  support using boards specified inside KERNEL_AFDO_VERIFIER_BOARDS.
-  """
-  return board in KERNEL_AFDO_VERIFIER_BOARDS
-
-
-def CheckAFDOArtifactExists(buildroot, chrome_root, board, target):
-  """Check if the artifact to upload in the builder already exists or not.
-
-  Args:
-    buildroot: The path to build root.
-    chrome_root: The path to Chrome root.
-    board: The name of the board.
-    target: The target to check. It can be one of:
-      "orderfile_generate": We need to check if the name of the orderfile to
-      generate is already in the GS bucket or not.
-      "orderfile_verify": We need to find if the latest unvetted orderfile is
-      already verified or not.
-      "benchmark_afdo": We need to check if the name of the benchmark AFDO
-      profile is already in the GS bucket or not.
-      "kernel_afdo": We need to check if the latest unvetted kernel profile is
-      already verified or not.
-      "chrome_afdo": We need to check if a release profile created with
-      latest unvetted benchmark and CWP profiles is already verified or not.
-
-  Returns:
-    True if exists. False otherwise.
-
-  Raises:
-    ValueError if the target is invalid.
-  """
-  gs_context = gs.GSContext()
-  if target == 'orderfile_generate':
-    # For orderfile_generate builder, get the orderfile name from chrome ebuild
-    orderfile_name = _GetOrderfileName(chrome_root)
-    # Need to append the suffix
-    orderfile_name += '.orderfile'
-    return gs_context.Exists(
-        os.path.join(ORDERFILE_GS_URL_UNVETTED,
-                     orderfile_name + XZ_COMPRESSION_SUFFIX))
-
-  if target == 'orderfile_verify':
-    # Check if the latest unvetted orderfile is already verified
-    orderfile_name = _FindLatestAFDOArtifact(ORDERFILE_GS_URL_UNVETTED,
-                                             _RankValidOrderfiles)
-    return gs_context.Exists(
-        os.path.join(ORDERFILE_GS_URL_VETTED, orderfile_name))
-
-  if target == 'benchmark_afdo':
-    # For benchmark_afdo_generate builder, get the name from chrome ebuild
-    afdo_name = _GetBenchmarkAFDOName(buildroot, board)
-    return gs_context.Exists(
-        os.path.join(BENCHMARK_AFDO_GS_URL, afdo_name + BZ2_COMPRESSION_SUFFIX))
-
-  if target == 'kernel_afdo':
-    # Check the latest unvetted kernel AFDO is already verified
-    source_url = os.path.join(KERNEL_PROFILE_URL,
-                              KERNEL_AFDO_VERIFIER_BOARDS[board])
-    dest_url = os.path.join(KERNEL_AFDO_GS_URL_VETTED,
-                            KERNEL_AFDO_VERIFIER_BOARDS[board])
-    afdo_name = _FindLatestAFDOArtifact(source_url, _RankValidCWPProfiles)
-    return gs_context.Exists(os.path.join(dest_url, afdo_name))
-
-  if target == 'chrome_afdo':
-    # Check the latest unvetted chrome AFDO profiles are verified
-    benchmark_afdo = _FindLatestAFDOArtifact(BENCHMARK_AFDO_GS_URL,
-                                             _RankValidBenchmarkProfiles)
-    arch = CHROME_AFDO_VERIFIER_BOARDS[board]
-    source_url = os.path.join(CWP_AFDO_GS_URL, arch)
-    cwp_afdo = _FindLatestAFDOArtifact(source_url, _RankValidCWPProfiles)
-    merged_name = MERGED_AFDO_NAME % (
-        _GetCombinedAFDOName(
-            _ParseCWPProfileName(os.path.splitext(cwp_afdo)[0]), arch,
-            _ParseBenchmarkProfileName(os.path.splitext(benchmark_afdo)[0])))
-    # The profile name also contained 'redacted' info
-    merged_name += '-redacted.afdo'
-    return gs_context.Exists(
-        os.path.join(RELEASE_AFDO_GS_URL_VETTED,
-                     merged_name + XZ_COMPRESSION_SUFFIX))
-
-  raise ValueError('Unsupported target %s to check' % target)
-
-
-def _UploadVettedAFDOArtifacts(artifact_type, subcategory=None):
-  """Upload vetted artifact type to GS bucket.
-
-  When we upload vetted artifacts, there is a race condition that
-  a new unvetted artifact might just be uploaded after the builder
-  starts. Thus we don't want to poll the bucket for latest vetted
-  artifact, and instead we look within the ebuilds.
-
-  Args:
-    artifact_type: The type of AFDO artifact to upload. Supports:
-    ('orderfile', 'kernel_afdo', 'benchmark_afdo', 'cwp_afdo')
-    subcategory: Optional. Name of subcategory, used to upload
-    kernel AFDO or CWP AFDO.
-
-  Returns:
-    Name of the AFDO artifact, if successfully uploaded. Otherwise
-    returns None.
-
-  Raises:
-    ValueError: if artifact_type is not supported, or subcategory
-    is not provided for kernel_afdo or cwp_afdo.
-  """
-  gs_context = gs.GSContext()
-  if artifact_type == 'orderfile':
-    artifact = _GetArtifactVersionInEbuild('chromeos-chrome',
-                                           'UNVETTED_ORDERFILE')
-    full_name = artifact + XZ_COMPRESSION_SUFFIX
-    source_url = os.path.join(ORDERFILE_GS_URL_UNVETTED, full_name)
-    dest_url = os.path.join(ORDERFILE_GS_URL_VETTED, full_name)
-  elif artifact_type == 'kernel_afdo':
-    if not subcategory:
-      raise ValueError('Subcategory is required for kernel_afdo.')
-    artifact = _GetArtifactVersionInEbuild(
-        'chromeos-kernel-' + subcategory.replace('.', '_'),
-        'AFDO_PROFILE_VERSION')
-    full_name = artifact + KERNEL_AFDO_COMPRESSION_SUFFIX
-    source_url = os.path.join(KERNEL_PROFILE_URL, subcategory, full_name)
-    dest_url = os.path.join(KERNEL_AFDO_GS_URL_VETTED, subcategory, full_name)
-  else:
-    raise ValueError('Only orderfile and kernel_afdo are supported.')
-
-  if gs_context.Exists(dest_url):
-    return None
-
-  logging.info('Copying artifact from %s to %s', source_url, dest_url)
-  gs_context.Copy(source_url, dest_url, acl='public-read')
-
-  return artifact
-
-
-def _PublishVettedAFDOArtifacts(json_file, uploaded, title=None):
-  """Publish the uploaded AFDO artifact to metadata.
-
-  Since there're no better ways for PUpr to keep track of uploading
-  new files in GS bucket, we need to commit a change to a metadata file
-  to reflect the upload.
-
-  Args:
-    json_file: The path to the JSON file that contains the metadata.
-    uploaded: Dict contains pairs of (package, artifact) showing the
-    newest name of uploaded 'artifact' to update for the 'package'.
-    title: Optional. Used for putting into commit message.
-
-  Raises:
-    PublishVettedAFDOArtifactsError:
-    if the artifact to update is not already in the metadata file, or
-    if the uploaded artifact is the same as in metadata file (no new
-    AFDO artifact uploaded). This should be caught earlier before uploading.
-  """
-  branch = git.GetTrackingBranch(
-      TOOLCHAIN_UTILS_PATH, for_checkout=False, for_push=True)
-
-  # Perform a git pull first to sync the checkout containing metadata,
-  # in case there are some updates during the builder was running.
-  # Possible race conditions are:
-  # (1) Concurrent running builders modifying the same file, but different
-  # entries. e.g. kernel_afdo.json containing three kernel profiles.
-  # Sync'ing in this case should be safe no matter what.
-  # (2) Concurrent updates to modify the same entry. This is unsafe because
-  # we might update an entry with an older profile. The checking logic in the
-  # function should guarantee we always update to a newer artifact, otherwise
-  # the builder fails.
-  git.RunGit(TOOLCHAIN_UTILS_PATH, ['pull', branch.remote], print_cmd=True)
-
-  afdo_versions = json.loads(osutils.ReadFile(json_file))
-  if title:
-    commit_message = title + '\n\n'
-  else:
-    commit_message = 'afdo_metadata: Publish new profiles.\n\n'
-
-  commit_body = 'Update %s from %s to %s\n'
-  for package, artifact in uploaded.items():
-    if not artifact:
-      # It's OK that one package has nothing to publish because it's not
-      # uploaded. The case of all packages have nothing to publish is already
-      # checked before this function.
-      continue
-    if package not in afdo_versions:
-      raise PublishVettedAFDOArtifactsError('The key %s is not in JSON file.' %
-                                            package)
-
-    old_value = afdo_versions[package]['name']
-
-    if package == 'benchmark':
-      update_to_newer_profile = _RankValidBenchmarkProfiles(
-          old_value) < _RankValidBenchmarkProfiles(artifact)
-    else:
-      update_to_newer_profile = _RankValidCWPProfiles(
-          old_value) < _RankValidCWPProfiles(artifact)
-    if not update_to_newer_profile:
-      raise PublishVettedAFDOArtifactsError(
-          'The artifact %s to update is not newer than the JSON file %s' %
-          (artifact, old_value))
-
-    afdo_versions[package]['name'] = artifact
-
-    commit_message += commit_body % (package, str(old_value), artifact)
-
-  pformat.json(afdo_versions, fp=json_file)
-
-  modifications = git.RunGit(
-      TOOLCHAIN_UTILS_PATH, ['status', '--porcelain', '-uno'],
-      capture_output=True,
-      print_cmd=True).output
-  if not modifications:
-    raise PublishVettedAFDOArtifactsError(
-        'AFDO info for the ebuilds did not change.')
-  logging.info('Git status: %s', modifications)
-  git_diff = git.RunGit(
-      TOOLCHAIN_UTILS_PATH, ['diff'], capture_output=True,
-      print_cmd=True).output
-  logging.info('Git diff: %s', git_diff)
-  # Commit the change
-  git.RunGit(
-      TOOLCHAIN_UTILS_PATH, ['commit', '-a', '-m', commit_message],
-      print_cmd=True)
-  # Push the change, this should create a CL, and auto-submit it.
-  git.GitPush(
-      TOOLCHAIN_UTILS_PATH,
-      'HEAD',
-      git.RemoteRef(branch.remote, f'{branch.ref}%submit'),
-      print_cmd=True)
-
-
-def _CreateReleaseChromeAFDO(cwp_afdo, arch, benchmark_afdo, output_dir):
-  """Create an AFDO profile to be used in release Chrome.
-
-  This means we want to merge the CWP and benchmark AFDO profiles into
-  one, and redact all ICF symbols.
-
-  Args:
-    cwp_afdo: Name of the verified CWP profile.
-    arch: Architecture name of the CWP profile.
-    benchmark_afdo: Name of the verified benchmark profile.
-    output_dir: A directory to store all artifacts.
-
-  Returns:
-    Full path to a generated release AFDO profile.
-  """
-  gs_context = gs.GSContext()
-  # Download profiles from gsutil.
-  cwp_full_name = cwp_afdo + XZ_COMPRESSION_SUFFIX
-  benchmark_full_name = benchmark_afdo + BZ2_COMPRESSION_SUFFIX
-
-  cwp_afdo_url = os.path.join(CWP_AFDO_GS_URL, arch, cwp_full_name)
-  cwp_afdo_local = os.path.join(output_dir, cwp_full_name)
-  gs_context.Copy(cwp_afdo_url, cwp_afdo_local)
-
-  benchmark_afdo_url = os.path.join(BENCHMARK_AFDO_GS_URL, benchmark_full_name)
-  benchmark_afdo_local = os.path.join(output_dir, benchmark_full_name)
-  gs_context.Copy(benchmark_afdo_url, benchmark_afdo_local)
-
-  # Decompress the files.
-  cwp_local_uncompressed = os.path.join(output_dir, cwp_afdo)
-  cros_build_lib.UncompressFile(cwp_afdo_local, cwp_local_uncompressed)
-  benchmark_local_uncompressed = os.path.join(output_dir, benchmark_afdo)
-  cros_build_lib.UncompressFile(benchmark_afdo_local,
-                                benchmark_local_uncompressed)
-
-  # Merge profiles.
-  merge_weights = [(cwp_local_uncompressed, RELEASE_CWP_MERGE_WEIGHT),
-                   (benchmark_local_uncompressed,
-                    RELEASE_BENCHMARK_MERGE_WEIGHT)]
-  merged_profile_name = MERGED_AFDO_NAME % (
-      _GetCombinedAFDOName(
-          _ParseCWPProfileName(cwp_afdo), arch,
-          _ParseBenchmarkProfileName(benchmark_afdo)))
-  merged_profile = os.path.join(output_dir, merged_profile_name)
-  _MergeAFDOProfiles(merge_weights, merged_profile)
-
-  # Redact profiles.
-  redacted_profile_name = merged_profile_name + '-redacted.afdo'
-  redacted_profile = os.path.join(output_dir, redacted_profile_name)
-  _RedactAFDOProfile(merged_profile, redacted_profile)
-
-  return redacted_profile
-
-
-def _UploadReleaseChromeAFDO():
-  """Upload an AFDO profile to be used in release Chrome.
-
-  Returns:
-    Full path to the release AFDO profile uploaded.
-  """
-  with osutils.TempDir() as tempdir:
-    # This path should be a full path to the profile
-    profile_path = _GetArtifactVersionInEbuild('chromeos-chrome',
-                                               'UNVETTED_AFDO_FILE')
-    # Compress the final AFDO profile.
-    ret = _CompressAFDOFiles([profile_path], None, tempdir,
-                             XZ_COMPRESSION_SUFFIX)
-    # Upload to GS bucket
-    _UploadAFDOArtifactToGSBucket(RELEASE_AFDO_GS_URL_VETTED, ret[0])
-
-    return profile_path
-
-
-def UploadAndPublishVettedAFDOArtifacts(artifact_type, board):
-  """Main function to upload a vetted AFDO artifact.
-
-  As suggested by the name, this function first uploads the vetted artifact
-  to GS bucket, and publishes the change to metadata file if needed.
-
-  Args:
-    artifact_type: Type of the artifact. 'Orderfile' or 'kernel_afdo'
-    board: Name of the board.
-
-  Returns:
-    Status of the upload and publish.
-  """
-
-  uploaded = {}
-  if artifact_type == 'chrome_afdo':
-    # For current board, there is a release AFDO in chroot used for
-    # verification.
-    uploaded['chrome-afdo'] = _UploadReleaseChromeAFDO()
-  elif artifact_type == 'kernel_afdo':
-    kver = KERNEL_AFDO_VERIFIER_BOARDS[board]
-    name = 'chromeos-kernel-' + kver.replace('.', '_')
-    uploaded[name] = _UploadVettedAFDOArtifacts(artifact_type, kver)
-    json_file = os.path.join(TOOLCHAIN_UTILS_PATH,
-                             'afdo_metadata/kernel_afdo.json')
-    title = 'afdo_metadata: Publish new profiles for kernel %s.' % kver
-  else:
-    uploaded['orderfile'] = _UploadVettedAFDOArtifacts('orderfile')
-
-  if not [x for x in uploaded.values() if x]:
-    # Nothing to publish to should be caught earlier
-    return False
-
-  if artifact_type == 'kernel_afdo':
-    # No need to publish orderfile or chrome AFDO changes.
-    # Skia autoroller can pick it up from uploads.
-    _PublishVettedAFDOArtifacts(json_file, uploaded, title)
-  return True
diff --git a/lib/toolchain_util_unittest.py b/lib/toolchain_util_unittest.py
index 6de3a34..dcd0b1a 100644
--- a/lib/toolchain_util_unittest.py
+++ b/lib/toolchain_util_unittest.py
@@ -12,7 +12,6 @@
 import io
 import json
 import os
-import re
 import shutil
 import time
 from unittest import mock
@@ -21,14 +20,11 @@
 from chromite.lib import constants
 from chromite.lib import cros_build_lib
 from chromite.lib import cros_test_lib
-from chromite.lib import git
 from chromite.lib import gob_util
 from chromite.lib import gs
-from chromite.lib import gs_unittest
 from chromite.lib import osutils
 from chromite.lib import partial_mock
 from chromite.lib import portage_util
-from chromite.lib import timeout_util
 from chromite.lib import toolchain_util
 from chromite.lib.parser import package_info
 
@@ -106,24 +102,6 @@
                  toolchain_util.CWPProfileVersion(
                      major=77, build=3809, patch=38, clock=1562580965)))
 
-  def testGetArtifactVersionInEbuild(self):
-    """Test top-level function _GetArtifactVersionInEbuild."""
-    package = 'package'
-    ebuild_file = os.path.join(self.tempdir, 'package.ebuild')
-    variables = ['variable_name', 'another_variable_name']
-    values = ['old-afdo-artifact-1.0', 'another-old-afdo-artifact-1.0']
-    ebuild_file_content = '\n'.join([
-        'Some message before',
-        '%s="%s"' % (variables[0], values[0]),
-        '%s="%s"' % (variables[1], values[1]), 'Some message after'
-    ])
-    osutils.WriteFile(ebuild_file, ebuild_file_content)
-    self.PatchObject(
-        toolchain_util, '_FindEbuildPath', return_value=ebuild_file)
-    for n, v in zip(variables, values):
-      ret = toolchain_util._GetArtifactVersionInEbuild(package, n)
-      self.assertEqual(ret, v)
-
   def testGetOrderfileName(self):
     """Test method _GetOrderfileName and related methods."""
     profile_name = ('chromeos-chrome-amd64-atom-77-3809.38-1562580965-'
@@ -153,6 +131,8 @@
         os.path.join(input_dir, targets[0]))
     # Should pass
     self.PatchObject(os.path, 'exists', return_value=True)
+    # Return ~1MB profile size.
+    self.PatchObject(os.path, 'getsize', return_value=100000)
     toolchain_util._CompressAFDOFiles(targets, input_dir, output_dir, suffix)
     compressed_names = [os.path.basename(x) for x in targets]
     inputs = [os.path.join(input_dir, n) for n in compressed_names]
@@ -279,24 +259,6 @@
         self.obj._GetOrderfileName())
     vers.assert_called_once()
 
-  def test_UpdateEbuildWithArtifacts(self):
-    """Test _UpdateEbuildWithArtifacts."""
-    func = self.PatchObject(self.obj, '_PatchEbuild')
-    self.obj._UpdateEbuildWithArtifacts('chromeos-chrome', {'var': 'val'})
-    info = toolchain_util._EbuildInfo(
-        path=self.chrome_ebuild, CPV=self.chrome_pkg)
-    info_9999 = toolchain_util._EbuildInfo(
-        path=os.path.realpath(
-            os.path.join(
-                os.path.dirname(__file__), '..', '..', 'src', 'third_party',
-                'chromiumos-overlay', 'chromeos-base', 'chromeos-chrome',
-                'chromeos-chrome-9999.ebuild')),
-        CPV=package_info.parse('chromeos-base/chromeos-chrome-9999'))
-    self.assertEqual([
-        mock.call(info, {'var': 'val'}, uprev=True),
-        mock.call(info_9999, {'var': 'val'}, uprev=False)
-    ], func.call_args_list)
-
 
 class PrepBundLatestAFDOArtifactTest(PrepareBundleTest):
   """Test related function to compare freshness of AFDO artifacts."""
@@ -399,8 +361,12 @@
   def setUp(self):
     self.artifact_type = 'Unspecified'
     self.input_artifacts = {}
-    self.profile_info = {}
+    self.kernel_version = '5_4'
+    self.profile_info = {
+        'kernel_version': self.kernel_version.replace('_', '.'),
+    }
     self.gsc_exists = None
+    self.patch_ebuild = mock.MagicMock()
     self.orderfile_name = (
         'chromeos-chrome-orderfile-field-78-3877.0-1567418235-'
         'benchmark-78.0.3893.0-r1.orderfile')
@@ -413,10 +379,8 @@
         toolchain_util._CommonPrepareBundle,
         '_FindLatestOrderfileArtifact',
         return_value=self.orderfile_name + toolchain_util.XZ_COMPRESSION_SUFFIX)
-    self.patch_ebuild = self.PatchObject(toolchain_util._CommonPrepareBundle,
-                                         '_PatchEbuild')
 
-  def SetUpPrepare(self, artifact_type, input_artifacts):
+  def SetUpPrepare(self, artifact_type, input_artifacts, mock_patch=True):
     """Set up to test _Prepare${artifactType}."""
     self.artifact_type = artifact_type
     self.input_artifacts = input_artifacts
@@ -429,6 +393,9 @@
     self.PatchObject(self.obj, '_GetOrderfileName', return_value='orderfile')
     self.gsc_exists = self.PatchObject(
         self.gs_context, 'Exists', return_value=True)
+    if mock_patch:
+      self.patch_ebuild = self.PatchObject(
+          toolchain_util._CommonPrepareBundle, '_PatchEbuild')
 
   def testPrepareUnverifiedChromeLlvmOrderfileExists(self):
     """Test that PrepareUnverfiedChromeLlvmOrderfile works when POINTLESS."""
@@ -530,6 +497,55 @@
       self.obj._CleanupArtifactDirectory('non/absolute/path')
     self.assertIn('needs to be an absolute path', str(context.exception))
 
+  def callPrepareVerifiedKernelCwpAfdoFile(self, ebuild_list_of_str):
+    cwp_loc = 'gs://path/to/cwp/kernel/5.4'
+    self.SetUpPrepare(
+        'VerifiedKernelCwpAfdoFile', {
+            'UnverifiedKernelCwpAfdoFile': [cwp_loc],
+            'VerifiedKernelCwpAfdoFile': [cwp_loc],
+        }, mock_patch=False)
+    cwp_old_ver = 'R99-14469.8-1644229953'
+    cwp_new_ver = 'R100-14496.0-1644834841'
+    kernel_cwp = os.path.join(cwp_loc, cwp_new_ver)
+    ebuild_info = toolchain_util._EbuildInfo(
+        path='/path/to/kernel-9999.ebuild', CPV=mock.MagicMock())
+
+    self.PatchObject(os, 'rename')
+    self.PatchObject(cros_build_lib, 'run')
+    self.PatchObject(toolchain_util, '_GetProfileAge', return_value=0)
+    self.PatchObject(self.obj, '_GetEbuildInfo', return_value=ebuild_info)
+    self.PatchObject(self.obj, '_FindLatestAFDOArtifact',
+                     return_value=kernel_cwp)
+    # The artifact is missing, build is needed.
+    self.gsc_exists.return_value = False
+    ebuild_old_str = ''.join(ebuild_list_of_str).format(
+        kernel_cwp_loc='', kernel_cwp_ver=cwp_old_ver)
+    # We are going to check how the mock_object was called.
+    mock_open = self.PatchObject(
+        builtins, 'open', mock.mock_open(read_data=(ebuild_old_str)))
+
+    self.obj.Prepare()
+
+    # Check the expected patched lines.
+    for ebuild_line in ebuild_list_of_str:
+      resolved_line = ebuild_line.format(kernel_cwp_loc=cwp_loc,
+                                         kernel_cwp_ver=cwp_new_ver)
+      self.assertIn(mock.call().write(resolved_line), mock_open.mock_calls)
+
+  def testPrepareVerifiedKernelCwpAfdoFileOldEbuild(self):
+    """Test PrepareVerifiedKernelCwpAfdoFile and patch old ebuild."""
+    ebuild_data = ('# some comment\n',
+                   'AFDO_LOCATION="{kernel_cwp_loc}"\n',
+                   'AFDO_PROFILE_VERSION="{kernel_cwp_ver}"')
+    self.callPrepareVerifiedKernelCwpAfdoFile(ebuild_data)
+
+  def testPrepareVerifiedKernelCwpAfdoFileNewEbuild(self):
+    """Test PrepareVerifiedKernelCwpAfdoFile and patch new ebuild."""
+    ebuild_data = ('# some comment\n',
+                   'export AFDO_LOCATION="{kernel_cwp_loc}"\n',
+                   'export AFDO_PROFILE_VERSION="{kernel_cwp_ver}"')
+    self.callPrepareVerifiedKernelCwpAfdoFile(ebuild_data)
+
 
 class BundleArtifactHandlerTest(PrepareBundleTest):
   """Test BundleArtifactHandler specific methods."""
@@ -559,10 +575,6 @@
     self.gen_order = self.PatchObject(
         toolchain_util.GenerateChromeOrderfile, 'Bundle', new=_Bundle)
     self.PatchObject(
-        toolchain_util._CommonPrepareBundle,
-        '_GetArtifactVersionInEbuild',
-        return_value=self.orderfile_name)
-    self.PatchObject(
         toolchain_util, '_GetOrderfileName', return_value=self.orderfile_name)
     self.copy2 = self.PatchObject(shutil, 'copy2')
 
@@ -602,12 +614,27 @@
   def testBundleVerifiedChromeLlvmOrderfileExists(self):
     """Test that BundleVerfiedChromeLlvmOrderfile works."""
     self.SetUpBundle('VerifiedChromeLlvmOrderfile')
+    self.PatchObject(
+        toolchain_util._CommonPrepareBundle,
+        '_GetArtifactVersionInEbuild',
+        return_value=self.orderfile_name)
     artifact = os.path.join(self.outdir, '%s.xz' % self.orderfile_name)
     self.assertEqual([artifact], self.obj.Bundle())
     self.copy2.assert_called_once_with(
         os.path.join(self.chroot.path, 'build', self.board, 'opt/google/chrome',
                      '%s.xz' % self.orderfile_name), artifact)
 
+  def testBundleVerifiedChromeLlvmOrderfileRaises(self):
+    """Test that BundleVerfiedChromeLlvmOrderfile raises exception."""
+    self.SetUpBundle('VerifiedChromeLlvmOrderfile')
+    # Chrome ebuild file is missing UNVETTED_ORDERFILE.
+    self.PatchObject(
+        builtins, 'open', mock.mock_open(read_data=''))
+    with self.assertRaisesRegex(
+        toolchain_util.BundleArtifactsHandlerError,
+        f'Could not find UNVETTED_ORDERFILE version in {constants.CHROME_PN}'):
+      self.obj.Bundle()
+
   def testBundleChromeClangWarningsFile(self):
     """Test that BundleChromeClangWarningsFile works."""
     self.SetUpBundle('ChromeClangWarningsFile')
@@ -673,6 +700,8 @@
             path=self.chrome_ebuild, CPV=self.chrome_pkg))
     run_command = self.PatchObject(cros_build_lib, 'run')
     sym_link_command = self.PatchObject(osutils, 'SafeSymlink')
+    # Return ~1MB profile size.
+    self.PatchObject(os.path, 'getsize', return_value=100000)
     mock_file_obj = io.StringIO()
     mock_open.return_value = mock_file_obj
 
@@ -704,6 +733,24 @@
     ]
     run_command.assert_has_calls(mock_calls)
 
+  @mock.patch.object(builtins, 'open')
+  def testBundleUnverifiedChromeBenchmarkAfdoFileRaisesError(self, mock_open):
+    self.SetUpBundle('UnverifiedChromeBenchmarkAfdoFile')
+    self.PatchObject(
+        self.obj,
+        '_GetEbuildInfo',
+        return_value=toolchain_util._EbuildInfo(
+            path=self.chrome_ebuild, CPV=self.chrome_pkg))
+    self.PatchObject(cros_build_lib, 'run')
+    self.PatchObject(osutils, 'SafeSymlink')
+    # Return invalid size of the profile.
+    self.PatchObject(os.path, 'getsize', return_value=100)
+    mock_file_obj = io.StringIO()
+    mock_open.return_value = mock_file_obj
+
+    with self.assertRaises(toolchain_util.BundleArtifactsHandlerError):
+      self.obj.Bundle()
+
   def testBundleChromeAFDOProfileForAndroidLinuxFailWhenNoBenchmark(self):
     self.SetUpBundle('ChromeAFDOProfileForAndroidLinux')
     merge_function = self.PatchObject(self.obj,
@@ -743,22 +790,51 @@
         print_cmd=True,
     )
 
-  def testBundleVerifiedKernelCwpAfdoFile(self):
+  def callBundleVerifiedKernelCwpAfdoFile(self, ebuild_data_list):
     self.SetUpBundle('VerifiedKernelCwpAfdoFile')
-    mock_ebuild = self.PatchObject(
-        self.obj, '_GetArtifactVersionInEbuild', return_value=self.kernel_name)
+    ebuild_info = toolchain_util._EbuildInfo(
+        path='/path/to/kernel-9999.ebuild', CPV=mock.MagicMock())
+    self.PatchObject(self.obj, '_GetEbuildInfo', return_value=ebuild_info)
+    ebuild_old_str = ''.join(ebuild_data_list)
+    # We are going to check how the mock_object was called.
+    self.PatchObject(
+        builtins, 'open', mock.mock_open(read_data=(ebuild_old_str)))
+
     ret = self.obj.Bundle()
     profile_name = self.kernel_name + (
         toolchain_util.KERNEL_AFDO_COMPRESSION_SUFFIX)
     verified_profile = os.path.join(self.outdir, profile_name)
     self.assertEqual([verified_profile], ret)
-    mock_ebuild.assert_called_once_with(
-        f'chromeos-kernel-{self.kernel_version}', 'AFDO_PROFILE_VERSION')
     profile_path = os.path.join(
         self.chroot.path, self.sysroot[1:], 'usr', 'lib', 'debug', 'boot',
         f'chromeos-kernel-{self.kernel_version}-{profile_name}')
     self.copy2.assert_called_once_with(profile_path, verified_profile)
 
+  def testBundleVerifiedKernelCwpAfdoFileOld(self):
+    """Test BundleVerifiedKernelCwpAfdoFile with the old ebuild."""
+    ebuild_data_list = ('# some comment\n',
+                        'AFDO_LOCATION=""\n',
+                        f'AFDO_PROFILE_VERSION="{self.kernel_name}"')
+    self.callBundleVerifiedKernelCwpAfdoFile(ebuild_data_list)
+
+  def testBundleVerifiedKernelCwpAfdoFileNew(self):
+    """Test BundleVerifiedKernelCwpAfdoFile with the new ebuild."""
+    ebuild_data_list = ('# some comment\n',
+                        'export AFDO_LOCATION=""\n',
+                        f'export AFDO_PROFILE_VERSION="{self.kernel_name}"')
+    self.callBundleVerifiedKernelCwpAfdoFile(ebuild_data_list)
+
+  def testBundleVerifiedKernelCwpAfdoFileRaises(self):
+    """Test that BundleVerifiedKernelCwpAfdoFile raises exception."""
+    # AFDO_PROFILE_VERSION is missing in the ebuild.
+    ebuild_data_list = ('# some comment\n',
+                        'AFDO_LOCATION=""')
+    with self.assertRaisesRegex(
+        toolchain_util.BundleArtifactsHandlerError,
+        'Could not find AFDO_PROFILE_VERSION in '
+        f'chromeos-kernel-{self.kernel_version}'):
+      self.callBundleVerifiedKernelCwpAfdoFile(ebuild_data_list)
+
   def runToolchainBundleTest(self, artifact_path, tarball_name, input_files,
                              expected_output_files):
     """Asserts that the given artifact_path is tarred up properly.
@@ -942,6 +1018,8 @@
       input_path = os.path.join(self.tempdir, 'input.afdo')
     if not output_path:
       output_path = os.path.join(self.tempdir, 'output.afdo')
+    # Return ~1MB profile size.
+    self.PatchObject(os.path, 'getsize', return_value=100000)
     self.obj._ProcessAFDOProfile(input_path, output_path, *args, **kwargs)
 
     self.run_command.assert_has_calls(expected_commands)
@@ -1009,6 +1087,14 @@
         remove=True,
         reduce_functions=reduce_functions)
 
+  def testProcessAFDOProfileRaisesError(self):
+    input_path = os.path.join(self.tempdir, 'input.afdo')
+    output_path = os.path.join(self.tempdir, 'output.afdo')
+    # Return invalid size of the profile.
+    self.PatchObject(os.path, 'getsize', return_value=100)
+    with self.assertRaises(toolchain_util.BundleArtifactsHandlerError):
+      self.obj._ProcessAFDOProfile(input_path, output_path)
+
   @mock.patch.object(builtins, 'open')
   def testProcessAFDOProfileForChromeOSReleaseProfile(self, mock_open):
     """Test call on _processAFDOProfile() for CrOS release profiles."""
@@ -1524,220 +1610,6 @@
     self.assertIn('has no handler in GetUpdatedFiles', str(context.exception))
 
 
-class FindEbuildPathTest(cros_test_lib.MockTempDirTestCase):
-  """Test top-level function _FindEbuildPath()."""
-
-  def setUp(self):
-    self.board = 'chell'
-    self.chrome_package = 'chromeos-chrome'
-    self.kernel_package = 'chromeos-kernel-3_18'
-    self.chrome_ebuild = (
-        '/mnt/host/source/src/path/to/chromeos-chrome-1.0.ebuild')
-    mock_result = cros_build_lib.CommandResult(output=self.chrome_ebuild)
-    self.mock_command = self.PatchObject(
-        cros_build_lib, 'run', return_value=mock_result)
-
-  # pylint: disable=protected-access
-  def testInvalidPackage(self):
-    """Test invalid package name."""
-    with self.assertRaises(ValueError) as context:
-      toolchain_util._FindEbuildPath('some-invalid-package')
-    self.assertIn('Invalid package name', str(context.exception))
-    self.mock_command.assert_not_called()
-
-  def testChromePackagePass(self):
-    """Test finding chrome ebuild work."""
-    ebuild_file = toolchain_util._FindEbuildPath(self.chrome_package)
-    cmd = ['equery', 'w', self.chrome_package]
-    self.mock_command.assert_called_with(
-        cmd, enter_chroot=True, stdout=True, encoding='utf-8')
-    self.assertEqual(ebuild_file, self.chrome_ebuild)
-
-  def testKernelPackagePass(self):
-    """Test finding kernel ebuild work."""
-    ebuild_path = (
-        '/mnt/host/source/src/path/to/chromeos-kernel-3_14-3.14-r1.ebuild')
-    mock_result = cros_build_lib.CommandResult(output=ebuild_path)
-    mock_command = self.PatchObject(
-        cros_build_lib, 'run', return_value=mock_result)
-    ebuild_file = toolchain_util._FindEbuildPath(self.kernel_package)
-    cmd = ['equery', 'w', self.kernel_package]
-    mock_command.assert_called_with(
-        cmd, enter_chroot=True, stdout=True, encoding='utf-8')
-    self.assertEqual(ebuild_file, ebuild_path)
-
-  def testPassWithBoardName(self):
-    """Test working with a board name."""
-    ebuild_file = toolchain_util._FindEbuildPath(
-        self.chrome_package, board='board')
-    cmd = ['equery-board', 'w', self.chrome_package]
-    self.mock_command.assert_called_with(
-        cmd, enter_chroot=True, stdout=True, encoding='utf-8')
-    self.assertEqual(ebuild_file, self.chrome_ebuild)
-
-  def testReturnPathOutsideChroot(self):
-    """Test returning correct path outside chroot."""
-    ebuild_file = toolchain_util._FindEbuildPath(
-        self.chrome_package, buildroot='/path/to/buildroot')
-    self.assertEqual(
-        ebuild_file,
-        '/path/to/buildroot/src/path/to/chromeos-chrome-1.0.ebuild')
-
-
-class LatestAFDOArtifactTest(cros_test_lib.RunCommandTempDirTestCase):
-  """Test related function to compare freshness of AFDO artifacts."""
-
-  # pylint: disable=protected-access
-  def setUp(self):
-    self.board = 'board'
-    self.gs_url = 'gs://path/to/any_gs_url'
-    self.current_branch = '78'
-    self.current_arch = 'atom'
-    self.MockListResult = collections.namedtuple('MockListResult',
-                                                 ('url', 'creation_time'))
-    files_in_gs_bucket = [
-        # Benchmark profiles
-        ('chromeos-chrome-amd64-78.0.3893.0_rc-r1.afdo.bz2', 2.0),
-        ('chromeos-chrome-amd64-78.0.3896.0_rc-r1.afdo.bz2', 1.0),  # Latest
-        ('chromeos-chrome-amd64-78.0.3897.0_rc-r1-merged.afdo.bz2', 3.0),
-        # CWP profiles
-        ('R78-3869.38-1562580965.afdo.xz', 2.1),
-        ('R78-3866.0-1570000000.afdo.xz', 1.1),  # Latest
-        ('R77-3811.0-1580000000.afdo.xz', 3.1),
-        # Kernel profiles
-        ('R76-3869.38-1562580965.gcov.xz', 1.3),
-        ('R76-3866.0-1570000000.gcov.xz', 2.3),  # Latest
-        # Orderfiles
-        ('chromeos-chrome-orderfile-field-78-3877.0-1567418235-'
-         'benchmark-78.0.3893.0-r1.orderfile.xz', 1.2),  # Latest
-        ('chromeos-chrome-orderfile-field-78-3877.0-1567418235-'
-         'benchmark-78.0.3850.0-r1.orderfile.xz', 2.2),
-    ]
-
-    self.gs_list = [
-        self.MockListResult(url=os.path.join(self.gs_url, x), creation_time=y)
-        for x, y in files_in_gs_bucket
-    ]
-    self.PatchObject(gs.GSContext, 'List', return_value=self.gs_list)
-    self.PatchObject(
-        toolchain_util,
-        '_FindCurrentChromeBranch',
-        return_value=self.current_branch)
-
-  def testFindCurrentChromeBranch(self):
-    """Test _FindCurrentChromeBranch() works correctly."""
-    chrome_name = 'chromeos-chrome-78.0.3893.0_rc-r1.ebuild'
-    self.PatchObject(
-        toolchain_util,
-        '_FindEbuildPath',
-        return_value=os.path.join('/path/to', chrome_name))
-    ret = toolchain_util._FindCurrentChromeBranch()
-    self.assertEqual(ret, self.current_branch)
-
-  def testFindLatestAFDOArtifactPassWithBenchmarkAFDO(self):
-    """Test _FindLatestAFDOArtifact returns latest benchmark AFDO."""
-    latest_afdo = toolchain_util._FindLatestAFDOArtifact(
-        self.gs_url, toolchain_util._RankValidBenchmarkProfiles)
-    self.assertEqual(latest_afdo,
-                     'chromeos-chrome-amd64-78.0.3896.0_rc-r1.afdo.bz2')
-
-  def testFindLatestAFDOArtifactPassWithCWPAFDO(self):
-    """Test _FindLatestAFDOArtifact return latest cwp AFDO."""
-    latest_afdo = toolchain_util._FindLatestAFDOArtifact(
-        self.gs_url, toolchain_util._RankValidCWPProfiles)
-    self.assertEqual(latest_afdo, 'R78-3866.0-1570000000.afdo.xz')
-
-  def testFindLatestAFDOArtifactPassWithKernelAFDO(self):
-    """Test _FindLatestAFDOArtifact return latest kernel AFDO."""
-    self.PatchObject(
-        toolchain_util, '_FindCurrentChromeBranch', return_value='76')
-    latest_afdo = toolchain_util._FindLatestAFDOArtifact(
-        self.gs_url, toolchain_util._RankValidCWPProfiles)
-    self.assertEqual(latest_afdo, 'R76-3866.0-1570000000.gcov.xz')
-
-  def testFindLatestAFDOArtifactPassWithOrderfile(self):
-    """Test _FindLatestAFDOArtifact return latest orderfile."""
-    latest_orderfile = toolchain_util._FindLatestAFDOArtifact(
-        self.gs_url, toolchain_util._RankValidOrderfiles)
-    self.assertEqual(
-        latest_orderfile,
-        'chromeos-chrome-orderfile-field-78-3877.0-1567418235-'
-        'benchmark-78.0.3893.0-r1.orderfile.xz')
-
-  def testFindLatestAFDOArtifactPassOnLastBranch(self):
-    """Test returns latest file on last branch when current has none."""
-    self.PatchObject(
-        toolchain_util, '_FindCurrentChromeBranch', return_value='79')
-    self.testFindLatestAFDOArtifactPassWithBenchmarkAFDO()
-
-  def testFindLatestAFDOArtifactFailToFindAnyFiles(self):
-    """Test function fails when no files on current branch."""
-    self.PatchObject(
-        toolchain_util, '_FindCurrentChromeBranch', return_value='80')
-    with self.assertRaises(RuntimeError) as context:
-      self.testFindLatestAFDOArtifactPassWithBenchmarkAFDO()
-
-    self.assertEqual('No files found on %s for branch 80' % self.gs_url,
-                     str(context.exception))
-
-  def testFindLatestAFDOArtifactsFindMaxFromInvalidFiles(self):
-    """Test function fails when searching max from list of invalid files."""
-    mock_gs_list = [
-        self.MockListResult(
-            url=os.path.join(self.gs_url, 'Invalid-name-but-end-in-78.afdo'),
-            creation_time=1.0)
-    ]
-    self.PatchObject(gs.GSContext, 'List', return_value=mock_gs_list)
-    with self.assertRaises(RuntimeError) as context:
-      toolchain_util._FindLatestAFDOArtifact(
-          self.gs_url, toolchain_util._RankValidBenchmarkProfiles)
-    self.assertIn('No valid latest artifact was found', str(context.exception))
-
-
-class UploadAFDOArtifactToGSBucketTest(gs_unittest.AbstractGSContextTest):
-  """Test top-level function _UploadAFDOArtifactToGSBucket."""
-
-  # pylint: disable=protected-access
-  def setUp(self):
-    self.gs_url = 'gs://some/random/gs/url'
-    self.local_path = '/path/to/file'
-    self.rename = 'new_file_name'
-    self.url_without_renaming = os.path.join(self.gs_url, 'file')
-    self.url_with_renaming = os.path.join(self.gs_url, 'new_file_name')
-    self.mock_copy = self.PatchObject(gs.GSContext, 'Copy')
-
-  def testFileToUploadNotExistTriggerException(self):
-    """Test the file to upload doesn't exist in the local path."""
-    with self.assertRaises(RuntimeError) as context:
-      toolchain_util._UploadAFDOArtifactToGSBucket(self.gs_url, self.local_path)
-    self.assertIn('to upload does not exist', str(context.exception))
-
-  def testFileToUploadAlreadyInBucketSkipsException(self):
-    """Test uploading a file that already exists in the bucket."""
-    self.PatchObject(os.path, 'exists', return_value=True)
-    mock_exist = self.PatchObject(gs.GSContext, 'Exists', return_value=True)
-    toolchain_util._UploadAFDOArtifactToGSBucket(self.gs_url, self.local_path)
-    mock_exist.assert_called_once_with(self.url_without_renaming)
-    self.mock_copy.assert_not_called()
-
-  def testFileUploadSuccessWithoutRenaming(self):
-    """Test successfully upload a file without renaming."""
-    self.PatchObject(os.path, 'exists', return_value=True)
-    self.PatchObject(gs.GSContext, 'Exists', return_value=False)
-    toolchain_util._UploadAFDOArtifactToGSBucket(self.gs_url, self.local_path)
-    self.mock_copy.assert_called_once_with(
-        self.local_path, self.url_without_renaming, acl='public-read')
-
-  def testFileUploadSuccessWithRenaming(self):
-    """Test successfully upload a file with renaming."""
-    self.PatchObject(os.path, 'exists', return_value=True)
-    self.PatchObject(gs.GSContext, 'Exists', return_value=False)
-    toolchain_util._UploadAFDOArtifactToGSBucket(self.gs_url, self.local_path,
-                                                 self.rename)
-    self.mock_copy.assert_called_once_with(
-        self.local_path, self.url_with_renaming, acl='public-read')
-
-
 class GenerateChromeOrderfileTest(cros_test_lib.MockTempDirTestCase):
   """Test GenerateChromeOrderfile class."""
 
@@ -1820,10 +1692,8 @@
         return_value=chrome_orderfile)
 
     self.PatchObject(toolchain_util.GenerateChromeOrderfile, '_CheckArguments')
-    mock_upload = self.PatchObject(toolchain_util,
-                                   '_UploadAFDOArtifactToGSBucket')
 
-    self.test_obj.Perform()
+    self.test_obj.Bundle()
 
     # Make sure the tarballs are inside the output directory
     output_files = os.listdir(self.out_dir)
@@ -1833,920 +1703,3 @@
     self.assertIn(
         self.orderfile_name + '.orderfile' +
         toolchain_util.XZ_COMPRESSION_SUFFIX, output_files)
-    self.assertEqual(mock_upload.call_count, 2)
-
-
-class UpdateEbuildWithAFDOArtifactsTest(cros_test_lib.MockTempDirTestCase):
-  """Test UpdateEbuildWithAFDOArtifacts class."""
-
-  # pylint: disable=protected-access
-  def setUp(self):
-    self.board = 'board'
-    self.package = 'valid-package'
-    self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
-    self.variable_name = 'VARIABLE_NAME'
-    self.variable_value = 'new-afdo-artifact-1.1'
-    self.test_obj = toolchain_util.UpdateEbuildWithAFDOArtifacts(
-        self.board, self.package, {self.variable_name: self.variable_value})
-
-  def testPatchEbuildFailWithoutMarkers(self):
-    """Test _PatchEbuild() fail if the ebuild has no valid markers."""
-    ebuild_file = os.path.join(self.tempdir, self.package + '.ebuild')
-    osutils.Touch(ebuild_file)
-    with self.assertRaises(
-        toolchain_util.UpdateEbuildWithAFDOArtifactsError) as context:
-      self.test_obj._PatchEbuild(ebuild_file)
-
-    self.assertEqual(
-        'Ebuild file does not have appropriate marker for AFDO/orderfile.',
-        str(context.exception))
-
-  def testPatchEbuildWithOneRule(self):
-    """Test _PatchEbuild() works with only one rule to replace."""
-    ebuild_file = os.path.join(self.tempdir, self.package + '.ebuild')
-    ebuild_file_content = '\n'.join([
-        'Some message before',
-        '%s="old-afdo-artifact-1.0"' % self.variable_name, 'Some message after'
-    ])
-    osutils.WriteFile(ebuild_file, ebuild_file_content)
-
-    self.test_obj._PatchEbuild(ebuild_file)
-
-    # Make sure temporary file is removed
-    self.assertNotIn(self.package + '.ebuild.new', os.listdir(self.tempdir))
-
-    # Make sure the artifact is updated
-    pattern = re.compile(toolchain_util.AFDO_ARTIFACT_EBUILD_REGEX %
-                         self.variable_name)
-    found = False
-    with open(ebuild_file) as f:
-      for line in f:
-        matched = pattern.match(line)
-        if matched:
-          found = True
-          self.assertEqual(matched.group('name')[1:-1], self.variable_value)
-
-    self.assertTrue(found)
-
-  def testPatchEbuildWithMultipleRulesPass(self):
-    """Test _PatchEbuild() works with multiple rules to replace."""
-    ebuild_file = os.path.join(self.tempdir, self.package + '.ebuild')
-    another_variable_name = 'VARIABLE_NAME2'
-    another_variable_value = 'another-new-afdo-artifact-2.0'
-    ebuild_file_content = '\n'.join([
-        'Some message before',
-        '%s="old-afdo-artifact-1.0"' % self.variable_name,
-        '%s="another-old-afdo-artifact-1.0"' % another_variable_name,
-        'Some message after'
-    ])
-    osutils.WriteFile(ebuild_file, ebuild_file_content)
-
-    test_obj = toolchain_util.UpdateEbuildWithAFDOArtifacts(
-        self.board, self.package, {
-            self.variable_name: self.variable_value,
-            another_variable_name: another_variable_value
-        })
-
-    test_obj._PatchEbuild(ebuild_file)
-
-    # Make sure all patterns are updated.
-    patterns = [
-        re.compile(toolchain_util.AFDO_ARTIFACT_EBUILD_REGEX %
-                   self.variable_name),
-        re.compile(toolchain_util.AFDO_ARTIFACT_EBUILD_REGEX %
-                   another_variable_name)
-    ]
-    values = [self.variable_value, another_variable_value]
-
-    found = 0
-    with open(ebuild_file) as f:
-      for line in f:
-        for p in patterns:
-          matched = p.match(line)
-          if matched:
-            found += 1
-            self.assertEqual(
-                matched.group('name')[1:-1], values[patterns.index(p)])
-            break
-
-    self.assertEqual(found, len(patterns))
-
-  def testPatchEbuildWithMultipleRulesFail(self):
-    """Test _PatchEbuild() fails when one marker not found in rules."""
-    ebuild_file = os.path.join(self.tempdir, self.package + '.ebuild')
-    ebuild_file_content = '\n'.join([
-        'Some message before',
-        '%s="old-afdo-artifact-1.0"' % self.variable_name, 'Some message after'
-    ])
-    osutils.WriteFile(ebuild_file, ebuild_file_content)
-
-    test_obj = toolchain_util.UpdateEbuildWithAFDOArtifacts(
-        self.board, self.package, {
-            self.variable_name: self.variable_value,
-            'another_variable_name': 'another_variable_value'
-        })
-
-    with self.assertRaises(
-        toolchain_util.UpdateEbuildWithAFDOArtifactsError) as context:
-      test_obj._PatchEbuild(ebuild_file)
-    self.assertEqual(
-        'Ebuild file does not have appropriate marker for AFDO/orderfile.',
-        str(context.exception))
-
-  def testUpdateManifest(self):
-    """Test _UpdateManifest() works properly."""
-    ebuild_file = os.path.join(self.tempdir, self.package + '.ebuild')
-    cmd = ['ebuild-%s' % self.board, ebuild_file, 'manifest', '--force']
-    self.PatchObject(cros_build_lib, 'run')
-    self.test_obj._UpdateManifest(ebuild_file)
-    cros_build_lib.run.assert_called_with(cmd, enter_chroot=True)
-
-
-class CheckAFDOArtifactExistsTest(cros_test_lib.RunCommandTempDirTestCase):
-  """Test CheckAFDOArtifactExists command."""
-
-  def setUp(self):
-    self.orderfile_name = 'any_orderfile_name'
-    self.afdo_name = 'any_name.afdo'
-    self.PatchObject(
-        toolchain_util, '_FindCurrentChromeBranch', return_value='78')
-
-  def _CheckExistCall(self, target, url_to_check, board='board'):
-    """Helper function to check the Exists() call on a url."""
-    for exists in [False, True]:
-      mock_exist = self.PatchObject(gs.GSContext, 'Exists', return_value=exists)
-      ret = toolchain_util.CheckAFDOArtifactExists(
-          buildroot='buildroot',
-          chrome_root='chrome_root',
-          target=target,
-          board=board)
-      self.assertEqual(exists, ret)
-      mock_exist.assert_called_once_with(url_to_check)
-
-  def testOrderfileGenerateAsTarget(self):
-    """Test check orderfile for generation work properly."""
-    self.PatchObject(
-        toolchain_util, '_GetOrderfileName', return_value=self.orderfile_name)
-    self._CheckExistCall(
-        'orderfile_generate',
-        os.path.join(
-            toolchain_util.ORDERFILE_GS_URL_UNVETTED, self.orderfile_name +
-            '.orderfile' + toolchain_util.XZ_COMPRESSION_SUFFIX))
-
-  def testOrderfileVerifyAsTarget(self):
-    """Test check orderfile for verification work properly."""
-    self.PatchObject(
-        toolchain_util,
-        '_FindLatestAFDOArtifact',
-        return_value=self.orderfile_name)
-    self._CheckExistCall(
-        'orderfile_verify',
-        os.path.join(toolchain_util.ORDERFILE_GS_URL_VETTED,
-                     self.orderfile_name))
-
-  def testBenchmarkAFDOAsTarget(self):
-    """Test check benchmark AFDO generation work properly."""
-    self.PatchObject(
-        toolchain_util, '_GetBenchmarkAFDOName', return_value=self.afdo_name)
-    self._CheckExistCall(
-        'benchmark_afdo',
-        os.path.join(toolchain_util.BENCHMARK_AFDO_GS_URL,
-                     self.afdo_name + toolchain_util.BZ2_COMPRESSION_SUFFIX))
-
-  def testKernelAFDOAsTarget(self):
-    """Test check kernel AFDO verification work properly."""
-    self.PatchObject(
-        toolchain_util, '_FindLatestAFDOArtifact', return_value=self.afdo_name)
-    self._CheckExistCall(
-        'kernel_afdo',
-        os.path.join(toolchain_util.KERNEL_AFDO_GS_URL_VETTED, '3.18',
-                     self.afdo_name), 'chell')
-
-
-class AFDOUpdateEbuildTests(cros_test_lib.RunCommandTempDirTestCase):
-  """Test wrapper functions to update ebuilds for different types."""
-
-  mock_benchmark_afdo = 'chromeos-chrome-amd64-78.0.3877.0.afdo.bz2'
-  mock_cwp_afdo = {
-      'atom': 'R78-3877.0-1566814872.afdo.xz',
-      'bigcore': 'R78-3865.35-1566812043.afdo.xz'
-  }
-
-  @staticmethod
-  def mockFindChromeAFDO(url, _pattern):
-    """Mock toolchain_util._FindLatestAFDOArtifact for Chrome AFDO."""
-    if 'benchmark' in url:
-      return AFDOUpdateEbuildTests.mock_benchmark_afdo
-
-    for arch in AFDOUpdateEbuildTests.mock_cwp_afdo:
-      if arch in url:
-        return AFDOUpdateEbuildTests.mock_cwp_afdo[arch]
-
-  # pylint: disable=protected-access
-  def setUp(self):
-    self.board = 'eve'
-    self.arch = 'bigcore'
-    self.kver = '4_4'
-    self.orderfile = 'chrome.orderfile.xz'
-    self.orderfile_stripped = 'chrome.orderfile'
-    self.kernel = 'R78-12345.0-1564997810.gcov.xz'
-    self.kernel_stripped = 'R78-12345.0-1564997810'
-    self.mock_obj = self.PatchObject(
-        toolchain_util, 'UpdateEbuildWithAFDOArtifacts', autospec=True)
-    self.chrome_branch = '78'
-    self.mock_branch = self.PatchObject(
-        toolchain_util,
-        '_FindCurrentChromeBranch',
-        return_value=self.chrome_branch)
-    self.mock_send_email_log = self.PatchObject(
-        toolchain_util.alerts, 'SendEmailLog')
-    self.PatchObject(
-        toolchain_util, '_FindCurrentChromeBranch', return_value='78')
-    self.PatchObject(osutils.TempDir, '__enter__', return_value=self.tempdir)
-
-  def testOrderfileUpdateChromePass(self):
-    """Test OrderfileUpdateChromeEbuild() calls other functions correctly."""
-    mock_find = self.PatchObject(
-        toolchain_util, '_FindLatestAFDOArtifact', return_value=self.orderfile)
-
-    toolchain_util.OrderfileUpdateChromeEbuild(self.board)
-    mock_find.assert_called_once_with(toolchain_util.ORDERFILE_GS_URL_UNVETTED,
-                                      toolchain_util._RankValidOrderfiles)
-    self.mock_obj.assert_called_with(
-        board=self.board,
-        package='chromeos-chrome',
-        update_rules={'UNVETTED_ORDERFILE': self.orderfile_stripped})
-
-  # pylint: disable=protected-access
-  def testAFDOUpdateChromeEbuildPass(self):
-    """Test AFDOUpdateChromeEbuild() calls other functions correctly."""
-    mock_find = self.PatchObject(
-        toolchain_util,
-        '_FindLatestAFDOArtifact',
-        side_effect=self.mockFindChromeAFDO)
-
-    afdo_name = 'any_name_for_merged.afdo'
-    mock_create = self.PatchObject(
-        toolchain_util, '_CreateReleaseChromeAFDO', return_value=afdo_name)
-    self.PatchObject(os, 'rename')
-
-    ret = toolchain_util.AFDOUpdateChromeEbuild(self.board)
-    self.assertTrue(ret)
-
-    calls = [
-        mock.call(toolchain_util.BENCHMARK_AFDO_GS_URL,
-                  toolchain_util._RankValidBenchmarkProfiles),
-        mock.call(
-            os.path.join(toolchain_util.CWP_AFDO_GS_URL, self.arch),
-            toolchain_util._RankValidCWPProfiles),
-    ]
-    mock_find.assert_has_calls(calls)
-    mock_create.assert_called_with(
-        os.path.splitext(self.mock_cwp_afdo[self.arch])[0], self.arch,
-        os.path.splitext(self.mock_benchmark_afdo)[0], self.tempdir)
-    self.mock_obj.assert_called_with(
-        board=self.board,
-        package='chromeos-chrome',
-        update_rules={'UNVETTED_AFDO_FILE': os.path.join('/tmp', afdo_name)})
-
-  # pylint: disable=protected-access
-  def testAFDOUpdateKernelEbuildPass(self):
-    """Test AFDOUpdateKernelEbuild() calls other functions correctly."""
-    mock_age = self.PatchObject(
-        toolchain_util, '_GetProfileAge', return_value=0)
-    mock_find = self.PatchObject(
-        toolchain_util, '_FindLatestAFDOArtifact', return_value=self.kernel)
-
-    ret = toolchain_util.AFDOUpdateKernelEbuild(self.board)
-
-    self.assertTrue(ret)
-
-    url = os.path.join(toolchain_util.KERNEL_PROFILE_URL,
-                       self.kver.replace('_', '.'))
-    mock_find.assert_called_once_with(url, toolchain_util._RankValidCWPProfiles)
-    mock_age.assert_called_once_with(self.kernel_stripped, 'kernel_afdo')
-
-    self.mock_send_email_log.assert_not_called()
-
-    self.mock_obj.assert_called_with(
-        board=self.board,
-        package='chromeos-kernel-' + self.kver,
-        update_rules={'AFDO_PROFILE_VERSION': self.kernel_stripped})
-
-  def testAFDOUpdateKernelEbuildFailDueToExpire(self):
-    """Test AFDOUpdateKernelEbuild() fails when the profile expires."""
-    self.PatchObject(
-        toolchain_util,
-        '_GetProfileAge',
-        return_value=toolchain_util.KERNEL_ALLOWED_STALE_DAYS + 1)
-    self.PatchObject(
-        toolchain_util, '_FindLatestAFDOArtifact', return_value=self.kernel)
-
-    ret = toolchain_util.AFDOUpdateKernelEbuild(self.board)
-
-    self.assertFalse(ret)
-
-  def testAFDOUpdateKernelEbuildWarnSheriff(self):
-    """Test AFDOUpdateKernelEbuild() warns sheriff when profile near expire."""
-    self.PatchObject(
-        toolchain_util,
-        '_GetProfileAge',
-        return_value=toolchain_util.KERNEL_ALLOWED_STALE_DAYS - 1)
-    self.PatchObject(
-        toolchain_util, '_FindLatestAFDOArtifact', return_value=self.kernel)
-    ret = toolchain_util.AFDOUpdateKernelEbuild(self.board)
-    self.assertTrue(ret)
-    self.mock_send_email_log.assert_called_once()
-    # Check kernel version in the subject.
-    self.assertIn(self.kver,
-                  self.mock_send_email_log.call_args[0][0])
-    # Check kernel version and kernel AFDO in the message body.
-    self.assertIn(self.kver,
-                  self.mock_send_email_log.call_args[1]['message'])
-    self.assertIn(self.kernel_stripped,
-                  self.mock_send_email_log.call_args[1]['message'])
-
-
-class GenerateBenchmarkAFDOProfile(cros_test_lib.MockTempDirTestCase):
-  """Test GenerateBenchmarkAFDOProfile class."""
-
-  # pylint: disable=protected-access
-  def setUp(self):
-    self.buildroot = self.tempdir
-    self.chroot_dir = os.path.join(self.tempdir, 'chroot')
-    osutils.SafeMakedirs(self.chroot_dir)
-    self.chroot_args = []
-    self.working_dir = os.path.join(self.chroot_dir, 'tmp')
-    osutils.SafeMakedirs(self.working_dir)
-    self.output_dir = os.path.join(self.tempdir, 'outdir')
-    self.package = 'chromeos-chrome'
-    version = '77.0.3863.0_rc'
-    revision = 1
-    self.version = f'{version}-r{revision}'
-    self.chrome_pkg = package_info.PackageInfo(
-        package=self.package, version=version, revision=revision)
-    self.board = 'board'
-    self.arch = 'amd64'
-    self.PatchObject(
-        portage_util, 'PortageqBestVisible', return_value=self.chrome_pkg)
-    self.PatchObject(portage_util, 'PortageqEnvvar')
-    self.test_obj = toolchain_util.GenerateBenchmarkAFDOProfile(
-        board=self.board,
-        output_dir=self.output_dir,
-        chroot_path=self.chroot_dir,
-        chroot_args=self.chroot_args)
-    self.test_obj.arch = self.arch
-
-  def testDecompressAFDOFile(self):
-    """Test _DecompressAFDOFile method."""
-    perf_data = 'perf.data.bz2'
-    to_decompress = os.path.join(self.working_dir, perf_data)
-    mock_uncompress = self.PatchObject(cros_build_lib, 'UncompressFile')
-    ret = self.test_obj._DecompressAFDOFile(to_decompress)
-    dest = os.path.join(self.working_dir, 'perf.data')
-    mock_uncompress.assert_called_once_with(to_decompress, dest)
-    self.assertEqual(ret, dest)
-
-  def testGetPerfAFDOName(self):
-    """Test _GetPerfAFDOName method."""
-    ret = self.test_obj._GetPerfAFDOName()
-    perf_data_name = toolchain_util.CHROME_PERF_AFDO_FILE % {
-        'package': self.package,
-        'arch': self.arch,
-        'versionnorev': self.version.split('_')[0]
-    }
-    self.assertEqual(ret, perf_data_name)
-
-  def testCheckAFDOPerfDataStatus(self):
-    """Test _CheckAFDOPerfDataStatus method."""
-    afdo_name = 'chromeos.afdo'
-    url = os.path.join(toolchain_util.BENCHMARK_AFDO_GS_URL,
-                       afdo_name + toolchain_util.BZ2_COMPRESSION_SUFFIX)
-    for exist in [True, False]:
-      mock_exist = self.PatchObject(gs.GSContext, 'Exists', return_value=exist)
-      self.PatchObject(
-          toolchain_util.GenerateBenchmarkAFDOProfile,
-          '_GetPerfAFDOName',
-          return_value=afdo_name)
-      ret_value = self.test_obj._CheckAFDOPerfDataStatus()
-      self.assertEqual(exist, ret_value)
-      mock_exist.assert_called_once_with(url)
-
-  def testWaitForAFDOPerfDataTimeOut(self):
-    """Test _WaitForAFDOPerfData method with timeout."""
-
-    def mock_timeout(*_args, **_kwargs):
-      raise timeout_util.TimeoutError
-
-    self.PatchObject(timeout_util, 'WaitForReturnTrue', new=mock_timeout)
-    ret = self.test_obj._WaitForAFDOPerfData()
-    self.assertFalse(ret)
-
-  def testWaitForAFDOPerfDataSuccess(self):
-    """Test method _WaitForAFDOPerfData() passes."""
-    mock_wait = self.PatchObject(timeout_util, 'WaitForReturnTrue')
-    afdo_name = 'perf.data'
-    mock_get = self.PatchObject(
-        toolchain_util.GenerateBenchmarkAFDOProfile,
-        '_GetPerfAFDOName',
-        return_value=afdo_name)
-    # TODO(crbug/1065172): Invalid assertion that had previously been mocked.
-    # mock_check =
-    self.PatchObject(toolchain_util.GenerateBenchmarkAFDOProfile,
-                     '_CheckAFDOPerfDataStatus')
-    mock_decompress = self.PatchObject(
-        toolchain_util.GenerateBenchmarkAFDOProfile, '_DecompressAFDOFile')
-    mock_copy = self.PatchObject(gs.GSContext, 'Copy')
-    self.test_obj._WaitForAFDOPerfData()
-    mock_wait.assert_called_once_with(
-        self.test_obj._CheckAFDOPerfDataStatus,
-        timeout=constants.AFDO_GENERATE_TIMEOUT,
-        period=constants.SLEEP_TIMEOUT)
-
-    # TODO(crbug/1065172): Invalid assertion that had previously been mocked.
-    # mock_check.assert_called_once()
-
-    # In actual program, this function should be called twice. But since
-    # its called _CheckAFDOPerfDataStatus() is mocked, it's only called once
-    # in this test.
-    mock_get.assert_called_once()
-    dest = os.path.join(self.working_dir, 'perf.data.bz2')
-    mock_decompress.assert_called_once_with(dest)
-    mock_copy.assert_called_once()
-
-  def testCreateAFDOFromPerfData(self):
-    """Test method _CreateAFDOFromPerfData()."""
-    # Intercept the real path to chrome binary
-    mock_chrome_debug = os.path.join(self.working_dir, 'chrome.debug')
-    toolchain_util._CHROME_DEBUG_BIN = mock_chrome_debug
-    osutils.Touch(mock_chrome_debug)
-    perf_name = 'chromeos-chrome-amd64-77.0.3849.0.perf.data'
-    self.PatchObject(
-        toolchain_util.GenerateBenchmarkAFDOProfile,
-        '_GetPerfAFDOName',
-        return_value=perf_name)
-    afdo_name = 'chromeos-chrome-amd64-77.0.3849.0_rc-r1.afdo'
-    self.PatchObject(
-        toolchain_util, '_GetBenchmarkAFDOName', return_value=afdo_name)
-    mock_command = self.PatchObject(cros_build_lib, 'run')
-    self.test_obj._CreateAFDOFromPerfData()
-    afdo_cmd = [
-        toolchain_util._AFDO_GENERATE_LLVM_PROF,
-        '--binary=/tmp/chrome.unstripped', '--profile=/tmp/' + perf_name,
-        '--out=/tmp/' + afdo_name
-    ]
-    mock_command.assert_called_once_with(
-        afdo_cmd,
-        enter_chroot=True,
-        capture_output=True,
-        print_cmd=True,
-        chroot_args=self.chroot_args)
-
-  def testUploadArtifacts(self):
-    """Test member _UploadArtifacts()."""
-    chrome_binary = 'chrome.unstripped'
-    afdo_name = 'chrome-1.0.afdo'
-    mock_upload = self.PatchObject(toolchain_util,
-                                   '_UploadAFDOArtifactToGSBucket')
-    self.test_obj._UploadArtifacts(chrome_binary, afdo_name)
-    chrome_version = toolchain_util.CHROME_ARCH_VERSION % {
-        'package': self.package,
-        'arch': self.arch,
-        'version': self.version
-    }
-    upload_name = (chrome_version + '.debug' +
-                   toolchain_util.BZ2_COMPRESSION_SUFFIX)
-    calls = [
-        mock.call(
-            toolchain_util.BENCHMARK_AFDO_GS_URL,
-            os.path.join(self.output_dir,
-                         chrome_binary + toolchain_util.BZ2_COMPRESSION_SUFFIX),
-            rename=upload_name),
-        mock.call(
-            toolchain_util.BENCHMARK_AFDO_GS_URL,
-            os.path.join(self.output_dir,
-                         afdo_name + toolchain_util.BZ2_COMPRESSION_SUFFIX))
-    ]
-    mock_upload.assert_has_calls(calls)
-
-  def testGenerateAFDOData(self):
-    """Test main function of _GenerateAFDOData()."""
-    chrome_binary = toolchain_util._CHROME_DEBUG_BIN % {
-        'root': self.chroot_dir,
-        'sysroot': os.path.join('build', self.board)
-    }
-    afdo_name = 'chrome.afdo'
-    mock_create = self.PatchObject(
-        self.test_obj, '_CreateAFDOFromPerfData', return_value=afdo_name)
-    mock_compress = self.PatchObject(toolchain_util, '_CompressAFDOFiles')
-    mock_upload = self.PatchObject(self.test_obj, '_UploadArtifacts')
-    ret = self.test_obj._GenerateAFDOData()
-    self.assertEqual(ret, afdo_name)
-    mock_create.assert_called_once_with()
-    calls = [
-        mock.call(
-            targets=[chrome_binary],
-            input_dir=None,
-            output_dir=self.output_dir,
-            suffix=toolchain_util.BZ2_COMPRESSION_SUFFIX),
-        mock.call(
-            targets=[afdo_name],
-            input_dir=self.working_dir,
-            output_dir=self.output_dir,
-            suffix=toolchain_util.BZ2_COMPRESSION_SUFFIX)
-    ]
-    mock_compress.assert_has_calls(calls)
-    mock_upload.assert_called_once_with(chrome_binary, afdo_name)
-
-
-class UploadVettedAFDOArtifactTest(cros_test_lib.MockTempDirTestCase):
-  """Test _UploadVettedAFDOArtifacts()."""
-
-  # pylint: disable=protected-access
-  def setUp(self):
-    self.artifact = 'some-artifact-1.0'
-    self.kver = '3.18'
-    self.cwp_arch = 'bigcore'
-    self.mock_get = self.PatchObject(
-        toolchain_util,
-        '_GetArtifactVersionInEbuild',
-        return_value=self.artifact)
-    self.mock_exist = self.PatchObject(
-        gs.GSContext, 'Exists', return_value=False)
-    self.mock_upload = self.PatchObject(gs.GSContext, 'Copy')
-
-  def testWrongArtifactType(self):
-    """Test wrong artifact_type raises exception."""
-    with self.assertRaises(ValueError) as context:
-      toolchain_util._UploadVettedAFDOArtifacts('wrong-type')
-    self.assertEqual('Only orderfile and kernel_afdo are supported.',
-                     str(context.exception))
-    self.mock_exist.assert_not_called()
-    self.mock_upload.assert_not_called()
-
-  def testArtifactExistInGSBucket(self):
-    """Test the artifact is already in the GS bucket."""
-    mock_exist = self.PatchObject(gs.GSContext, 'Exists', return_value=True)
-    ret = toolchain_util._UploadVettedAFDOArtifacts('orderfile')
-    mock_exist.assert_called_once()
-    self.assertIsNone(ret)
-
-  def testUploadVettedOrderfile(self):
-    """Test _UploadVettedAFDOArtifacts() works with orderfile."""
-    full_name = self.artifact + toolchain_util.XZ_COMPRESSION_SUFFIX
-    source_url = os.path.join(toolchain_util.ORDERFILE_GS_URL_UNVETTED,
-                              full_name)
-    dest_url = os.path.join(toolchain_util.ORDERFILE_GS_URL_VETTED, full_name)
-    ret = toolchain_util._UploadVettedAFDOArtifacts('orderfile')
-    self.mock_get.assert_called_once_with('chromeos-chrome',
-                                          'UNVETTED_ORDERFILE')
-    self.mock_exist.assert_called_once_with(dest_url)
-    self.mock_upload.assert_called_once_with(
-        source_url, dest_url, acl='public-read')
-    self.assertEqual(ret, self.artifact)
-
-  def testUploadVettedKernelAFDO(self):
-    """Test _UploadVettedAFDOArtifacts() works with kernel afdo."""
-    full_name = self.artifact + toolchain_util.KERNEL_AFDO_COMPRESSION_SUFFIX
-    source_url = os.path.join(toolchain_util.KERNEL_PROFILE_URL, self.kver,
-                              full_name)
-    dest_url = os.path.join(toolchain_util.KERNEL_AFDO_GS_URL_VETTED, self.kver,
-                            full_name)
-    ret = toolchain_util._UploadVettedAFDOArtifacts('kernel_afdo', self.kver)
-    self.mock_get.assert_called_once_with(
-        'chromeos-kernel-' + self.kver.replace('.', '_'),
-        'AFDO_PROFILE_VERSION')
-    self.mock_exist.assert_called_once_with(dest_url)
-    self.mock_upload.assert_called_once_with(
-        source_url, dest_url, acl='public-read')
-    self.assertEqual(ret, self.artifact)
-
-
-class PublishVettedAFDOArtifactTest(cros_test_lib.MockTempDirTestCase):
-  """Test _PublishVettedAFDOArtifacts()."""
-
-  # pylint: disable=protected-access
-  def setUp(self):
-    self.package = 'atom'
-    self.package2 = 'benchmark'
-    self.afdo_sorted_by_freshness = [
-        'R78-3865.0-1560000000.afdo', 'R78-3869.38-1562580965.afdo',
-        'R78-3866.0-1570000000.afdo'
-    ]
-    self.uploaded_invalid = {
-        self.package: self.afdo_sorted_by_freshness[0],
-        self.package2: None
-    }
-    self.uploaded = {
-        self.package: self.afdo_sorted_by_freshness[2],
-        self.package2: None
-    }
-    # Prepare a JSON file containing metadata
-    toolchain_util.TOOLCHAIN_UTILS_PATH = self.tempdir
-    osutils.SafeMakedirs(os.path.join(self.tempdir, 'afdo_metadata'))
-    self.json_file = os.path.join(self.tempdir,
-                                  'afdo_metadata/kernel_afdo.json')
-    self.afdo_versions = {
-        self.package: {
-            'name': self.afdo_sorted_by_freshness[1],
-        },
-        self.package2: {
-            'name': 'R1234',
-        },
-        'some-package-should-not-change': {
-            'name': 'R5678-1234',
-        },
-    }
-
-    with open(self.json_file, 'w') as f:
-      json.dump(self.afdo_versions, f)
-    self.PatchObject(
-        git, 'GetTrackingBranch', return_value=git.RemoteRef('origin', 'main'))
-    GitStatus = collections.namedtuple('GitStatus', ['output'])
-    self.mock_git = self.PatchObject(
-        git, 'RunGit', return_value=GitStatus(output='non-empty'))
-
-  def testPublishOlderArtifactThanInMetadataFailure(self):
-    """Test failure when publishing an older metadata as than JSON file."""
-    with self.assertRaises(
-        toolchain_util.PublishVettedAFDOArtifactsError) as context:
-      toolchain_util._PublishVettedAFDOArtifacts(self.json_file,
-                                                 self.uploaded_invalid)
-    self.assertIn('to update is not newer than the JSON file',
-                  str(context.exception))
-
-  def testPublishUploadedProfilesPass(self):
-    """Test successfully publish metadata for uploaded profiles."""
-    toolchain_util._PublishVettedAFDOArtifacts(self.json_file, self.uploaded)
-
-    # Check changes in JSON file
-    new_afdo_versions = json.loads(osutils.ReadFile(self.json_file))
-    self.assertEqual(len(self.afdo_versions), len(new_afdo_versions))
-    self.assertEqual(new_afdo_versions[self.package]['name'],
-                     self.uploaded[self.package])
-    for k in self.afdo_versions:
-      # Make sure other fields are not changed
-      if k != self.package:
-        self.assertEqual(self.afdo_versions[k], new_afdo_versions[k])
-
-    # Check the git calls correct
-    message = 'afdo_metadata: Publish new profiles.\n\n'
-    message += 'Update %s from %s to %s\n' % (self.package,
-                                              self.afdo_sorted_by_freshness[1],
-                                              self.afdo_sorted_by_freshness[2])
-    calls = [
-        mock.call(self.tempdir, ['pull', 'origin'], print_cmd=True),
-        mock.call(
-            self.tempdir, ['status', '--porcelain', '-uno'],
-            capture_output=True,
-            print_cmd=True),
-        mock.call(self.tempdir, ['diff'], capture_output=True, print_cmd=True),
-        mock.call(
-            self.tempdir, ['commit', '-a', '-m', message], print_cmd=True),
-        mock.call(
-            self.tempdir, ['push', 'origin', 'HEAD:main%submit'],
-            capture_output=True,
-            print_cmd=True)
-    ]
-    self.mock_git.assert_has_calls(calls)
-
-
-class UploadReleaseChromeAFDOTest(cros_test_lib.MockTempDirTestCase):
-  """Test _UploadReleaseChromeAFDO() and related functions."""
-
-  # pylint: disable=protected-access
-  def setUp(self):
-    self.cwp_name = 'R77-3809.38-1562580965.afdo'
-    self.cwp_full = self.cwp_name + toolchain_util.XZ_COMPRESSION_SUFFIX
-    self.arch = 'atom'
-    self.benchmark_name = 'chromeos-chrome-amd64-77.0.3849.0_rc-r1.afdo'
-    self.benchmark_full = (self.benchmark_name +
-                           toolchain_util.BZ2_COMPRESSION_SUFFIX)
-    cwp_string = '%s-77-3809.38-1562580965' % self.arch
-    benchmark_string = 'benchmark-77.0.3849.0-r1'
-    self.merged_name = 'chromeos-chrome-amd64-%s-%s' % (cwp_string,
-                                                        benchmark_string)
-    self.redacted_name = self.merged_name + '-redacted.afdo'
-    self.output = os.path.join(
-        self.tempdir, self.redacted_name + toolchain_util.XZ_COMPRESSION_SUFFIX)
-    self.decompress = self.PatchObject(cros_build_lib, 'UncompressFile')
-    self.compress = self.PatchObject(
-        toolchain_util, '_CompressAFDOFiles', return_value=[self.output])
-    self.upload = self.PatchObject(toolchain_util,
-                                   '_UploadAFDOArtifactToGSBucket')
-    self.run_command = self.PatchObject(cros_build_lib, 'run')
-    self.gs_copy = self.PatchObject(gs.GSContext, 'Copy')
-    self.PatchObject(osutils.TempDir, '__enter__', return_value=self.tempdir)
-
-  @mock.patch.object(builtins, 'open')
-  def testRedactAFDOProfile(self, mock_open):
-    """Test _RedactAFDOProfile() handles calls correctly."""
-    input_name = os.path.join(self.tempdir, self.merged_name)
-    input_to_text = input_name + '.text.temp'
-    redacted_temp = input_name + '.redacted.temp'
-    removed_temp = input_name + '.removed.temp'
-    reduced_temp = input_name + '.reduced.temp'
-    output_name = os.path.join(self.tempdir, self.redacted_name)
-
-    mock_file_obj = io.StringIO()
-    mock_open.return_value = mock_file_obj
-
-    toolchain_util._RedactAFDOProfile(input_name, output_name)
-
-    redact_calls = [
-        mock.call(
-            [
-                'llvm-profdata',
-                'merge',
-                '-sample',
-                '-text',
-                input_name,
-                '-output',
-                input_to_text,
-            ],
-            enter_chroot=True,
-            print_cmd=True,
-        ),
-        mock.call(
-            ['redact_textual_afdo_profile'],
-            input=mock_file_obj,
-            stdout=redacted_temp,
-            print_cmd=True,
-            enter_chroot=True,
-        ),
-        mock.call(
-            [
-                'remove_indirect_calls',
-                '--input=' + redacted_temp,
-                '--output=' + removed_temp,
-            ],
-            enter_chroot=True,
-            print_cmd=True,
-        ),
-        mock.call(
-            [
-                'remove_cold_functions',
-                '--input=' + removed_temp,
-                '--output=' + reduced_temp,
-                '--number=20000',
-            ],
-            enter_chroot=True,
-            print_cmd=True,
-        ),
-        mock.call(
-            [
-                'llvm-profdata',
-                'merge',
-                '-sample',
-                '-compbinary',
-                reduced_temp,
-                '-output',
-                output_name,
-            ],
-            enter_chroot=True,
-            print_cmd=True,
-        )
-    ]
-    self.run_command.assert_has_calls(redact_calls)
-
-  def testCreateReleaseChromeAFDOPass(self):
-    """Test _CreateReleaseChromeAFDO() handles naming and calls correctly."""
-    redact_call = self.PatchObject(toolchain_util, '_RedactAFDOProfile')
-
-    toolchain_util._CreateReleaseChromeAFDO(self.cwp_name, self.arch,
-                                            self.benchmark_name, self.tempdir)
-
-    # Check downloading files.
-    gs_copy_calls = [
-        mock.call(
-            os.path.join(toolchain_util.CWP_AFDO_GS_URL, self.arch,
-                         self.cwp_full),
-            os.path.join(self.tempdir, self.cwp_full)),
-        mock.call(
-            os.path.join(toolchain_util.BENCHMARK_AFDO_GS_URL,
-                         self.benchmark_full),
-            os.path.join(self.tempdir, self.benchmark_full))
-    ]
-    self.gs_copy.assert_has_calls(gs_copy_calls)
-
-    # Check decompress files.
-    decompress_calls = [
-        mock.call(
-            os.path.join(self.tempdir, self.cwp_full),
-            os.path.join(self.tempdir, self.cwp_name)),
-        mock.call(
-            os.path.join(self.tempdir, self.benchmark_full),
-            os.path.join(self.tempdir, self.benchmark_name))
-    ]
-    self.decompress.assert_has_calls(decompress_calls)
-
-    # Check call to merge.
-    merge_command = [
-        'llvm-profdata',
-        'merge',
-        '-sample',
-        '-output=' + os.path.join(self.tempdir, self.merged_name),
-        '-weighted-input=%d,%s' % (toolchain_util.RELEASE_CWP_MERGE_WEIGHT,
-                                   os.path.join(self.tempdir, self.cwp_name)),
-        '-weighted-input=%d,%s' %
-        (toolchain_util.RELEASE_BENCHMARK_MERGE_WEIGHT,
-         os.path.join(self.tempdir, self.benchmark_name)),
-    ]
-    self.run_command.assert_called_once_with(
-        merge_command, enter_chroot=True, print_cmd=True)
-
-    # Check calls to redact.
-    redact_call.assert_called_once_with(
-        os.path.join(self.tempdir, self.merged_name),
-        os.path.join(self.tempdir, self.redacted_name))
-
-  def testUploadReleaseChromeAFDOPass(self):
-    """Test _UploadReleaseChromeAFDO() handles naming and calls correctly."""
-    verified_afdo = os.path.join(self.tempdir, self.redacted_name)
-    self.PatchObject(
-        toolchain_util,
-        '_GetArtifactVersionInEbuild',
-        return_value=verified_afdo)
-
-    ret = toolchain_util._UploadReleaseChromeAFDO()
-    self.assertEqual(verified_afdo, ret)
-    # Check compress and upload.
-    self.compress.assert_called_once_with([os.path.join(verified_afdo)], None,
-                                          self.tempdir,
-                                          toolchain_util.XZ_COMPRESSION_SUFFIX)
-    self.upload.assert_called_once_with(
-        toolchain_util.RELEASE_AFDO_GS_URL_VETTED,
-        os.path.join(self.tempdir,
-                     self.redacted_name + toolchain_util.XZ_COMPRESSION_SUFFIX))
-
-
-class UploadAndPublishVettedAFDOArtifactsTest(cros_test_lib.MockTempDirTestCase
-                                             ):
-  """Test UploadAndPublishVettedAFDOArtifacts()."""
-
-  orderfile_name = 'chrome.orderfile'
-  kernel_afdo = 'kernel.afdo'
-
-  @staticmethod
-  def mockUploadVettedAFDOArtifacts(artifact_type, _subcategory=None):
-    if artifact_type == 'orderfile':
-      return UploadAndPublishVettedAFDOArtifactsTest.orderfile_name
-    if artifact_type == 'kernel_afdo':
-      return UploadAndPublishVettedAFDOArtifactsTest.kernel_afdo
-    return None
-
-  def setUp(self):
-    self.mock_upload = self.PatchObject(
-        toolchain_util,
-        '_UploadVettedAFDOArtifacts',
-        side_effect=self.mockUploadVettedAFDOArtifacts)
-    self.mock_publish = self.PatchObject(toolchain_util,
-                                         '_PublishVettedAFDOArtifacts')
-    self.mock_merge = self.PatchObject(toolchain_util,
-                                       '_UploadReleaseChromeAFDO')
-    self.board = 'chell'  # Chose chell to test kernel
-    self.kver = '3.18'
-    self.kernel_json = os.path.join(toolchain_util.TOOLCHAIN_UTILS_PATH,
-                                    'afdo_metadata/kernel_afdo.json')
-    self.chrome_json = os.path.join(toolchain_util.TOOLCHAIN_UTILS_PATH,
-                                    'afdo_metadata/chrome_afdo.json')
-
-  def testReturnFalseWhenNoArtifactUploaded(self):
-    """Test it returns False when no new artifacts are uploaded."""
-    mock_upload_nothing = self.PatchObject(
-        toolchain_util, '_UploadVettedAFDOArtifacts', return_value=None)
-    ret = toolchain_util.UploadAndPublishVettedAFDOArtifacts(
-        'orderfile', self.board)
-    self.assertFalse(ret)
-    mock_upload_nothing.assert_called_once_with('orderfile')
-    self.mock_publish.assert_not_called()
-
-  def testChromeAFDOPass(self):
-    """Make sure for chrome_afdo, it calls other functions correctly."""
-    mock_upload = self.PatchObject(toolchain_util, '_UploadReleaseChromeAFDO')
-    ret = toolchain_util.UploadAndPublishVettedAFDOArtifacts(
-        'chrome_afdo', self.board)
-    self.assertTrue(ret)
-    mock_upload.assert_called_once_with()
-    self.mock_publish.assert_not_called()
-
-  def testKernelAFDOPass(self):
-    """Make sure for kernel_afdo, it calls other functions correctly."""
-    ret = toolchain_util.UploadAndPublishVettedAFDOArtifacts(
-        'kernel_afdo', self.board)
-    self.assertTrue(ret)
-    uploaded = {
-        'chromeos-kernel-' + self.kver.replace('.', '_'): self.kernel_afdo
-    }
-    self.mock_upload.assert_called_once_with('kernel_afdo', self.kver)
-    self.mock_publish.assert_called_once_with(
-        self.kernel_json, uploaded,
-        'afdo_metadata: Publish new profiles for kernel %s.' % self.kver)
-
-  def testOrderfilePass(self):
-    """Make sure for orderfile, it calls other functions correctly."""
-    ret = toolchain_util.UploadAndPublishVettedAFDOArtifacts(
-        'orderfile', self.board)
-    self.assertTrue(ret)
-    self.mock_upload.assert_called_once_with('orderfile')
-    self.mock_publish.assert_not_called()
diff --git a/lib/unittest_lib.py b/lib/unittest_lib.py
index be633dd..a9ba6f8 100644
--- a/lib/unittest_lib.py
+++ b/lib/unittest_lib.py
@@ -8,6 +8,7 @@
 
 from chromite.lib import cros_build_lib
 from chromite.lib import osutils
+from chromite.lib import sysroot_lib
 
 
 class BuildELFError(Exception):
@@ -79,3 +80,19 @@
     raise BuildELFError('%s\n%s' % (e, e.result.error))
   finally:
     os.unlink(source_fn)
+
+
+def create_stub_make_conf(sysroot: os.PathLike):
+  """Creates a stub sysroot_lib._MAKE_CONF for tests to correctly read configs.
+
+  sysroot_lib expects sysroot_lib._MAKE_CONF (etc/make.conf) to exist and to
+  source sysroot_lib._MAKE_CONF_BOARD_SETUP (etc/make.conf.board_setup) to read
+  the config.  For tests to read their expected config, a stub _MAKE_CONF needs
+  to be created if they are using sysroot_lib.WriteConfig().
+
+  Args:
+    sysroot: The path to the sysroot
+  """
+  # pylint: disable=protected-access
+  osutils.WriteFile(os.path.join(sysroot, sysroot_lib._MAKE_CONF),
+                    'source make.conf.board_setup', makedirs=True)
diff --git a/lib/uprev_lib.py b/lib/uprev_lib.py
index 0540f7e..efe88b6 100644
--- a/lib/uprev_lib.py
+++ b/lib/uprev_lib.py
@@ -71,28 +71,35 @@
     return '%s-%s' % (self.package, self.version)
 
 
-def get_chrome_version_from_refs(refs):
-  """Get the chrome version to use from the list of provided tags.
+def get_version_from_refs(refs):
+  """Get the version to use from the list of provided tags.
+
+  Version strings are of format "78.0.3876.1".
 
   Args:
-    refs (list[GitRef]): The tags to parse for the best chrome version.
+    refs (list[GitRef]): The tags to parse for the best version.
 
   Returns:
-    str: The chrome version to use.
-  """
-  assert refs
+    str: The version to use.
 
-  # Each tag is a chrome version string, e.g. "78.0.3876.1", so extract the
+  Raises:
+    Exception: if no unstable ebuild exists for Chrome.
+  """
+  if not refs:
+    raise TypeError
+
+  # Each tag is a version string, e.g. "78.0.3876.1", so extract the
   # tag name from the ref, e.g. "refs/tags/78.0.3876.1".
   versions = [ref.ref.split('/')[-1] for ref in refs]
-  return best_chrome_version(versions)
+  return best_version(versions)
 
 
-def best_chrome_version(versions):
+def best_version(versions):
   # Convert each version from a string like "78.0.3876.1" to a list of ints
   # to compare them, find the most recent (max), and then reconstruct the
   # version string.
-  assert versions
+  if not versions:
+    raise TypeError
 
   version = max([int(part) for part in v.split('.')] for v in versions)
   return '.'.join(str(part) for part in version)
@@ -100,9 +107,10 @@
 
 def best_chrome_ebuild(ebuilds):
   """Determine the best/newest chrome ebuild from a list of ebuilds."""
-  assert ebuilds
+  if not ebuilds:
+    raise TypeError
 
-  version = best_chrome_version(ebuild.chrome_version for ebuild in ebuilds)
+  version = best_version(ebuild.chrome_version for ebuild in ebuilds)
   candidates = [
       ebuild for ebuild in ebuilds if ebuild.chrome_version == version
   ]
@@ -340,9 +348,9 @@
     # Case 1 - Uprev: self._version = 78.0.0.0, Candidate = 77.0.0.0
     # Case 2 - Uprev: self._version = 78.0.0.0, Candidate = 78.0.0.0
     # Case 3 - Skip:  self._version = 78.0.0.0, Candidate = 79.0.0.0
-    best_version = best_chrome_version(
+    version = best_version(
         [self._version, candidate.chrome_version])
-    if self._version == best_version:
+    if self._version == version:
       # Cases 1 and 2.
       return (True, candidate)
 
@@ -485,7 +493,7 @@
 
     Args:
       package_list (list[str]): A list of packages to uprev.
-      force: Boolean indicating whether or not to consider blacklisted ebuilds.
+      force: Boolean indicating whether or not to consider denylisted ebuilds.
     """
     # Use all found packages if an explicit package_list is not given.
     use_all = not bool(package_list)
@@ -593,7 +601,7 @@
         of whether they are in our set of packages.
       package_list (list[str]): A set of the packages we want to gather. If
       use_all is True, this argument is ignored, and should be None.
-      force: Boolean indicating whether or not to consider blacklisted ebuilds.
+      force: Boolean indicating whether or not to consider denylisted ebuilds.
     """
     # See crrev.com/c/1257944 for origins of this.
     root_version = manifest_version.VersionInfo.from_repo(constants.SOURCE_ROOT)
@@ -692,6 +700,21 @@
     self.modified.append(result)
     return self
 
+  def extend(self, other: 'UprevVersionedPackageResult'):
+    """Adds another result from an existing result."""
+    self.modified.extend(other.modified)
+
+  def __iadd__(self, other: 'UprevVersionedPackageResult'
+               ) -> 'UprevVersionedPackageResult':
+    """Adds another result from an existing result."""
+    self.extend(other)
+    return self
+
+  def __add__(self, other: 'UprevVersionedPackageResult'
+              ) -> 'UprevVersionedPackageResult':
+    """Adds two result objects to create a new one."""
+    return UprevVersionedPackageResult().extend(self).extend(other)
+
   @property
   def uprevved(self):
     return bool(self.modified)
diff --git a/lib/uprev_lib_unittest.py b/lib/uprev_lib_unittest.py
index 79352b9..eb7a8b7 100644
--- a/lib/uprev_lib_unittest.py
+++ b/lib/uprev_lib_unittest.py
@@ -24,7 +24,7 @@
 
 
 class ChromeVersionTest(cros_test_lib.TestCase):
-  """Tests for best_chrome_version and get_chrome_version_from_refs."""
+  """Tests for best_version and get_version_from_refs."""
 
   def setUp(self):
     # The tag ref template.
@@ -41,41 +41,41 @@
 
   def test_single_version(self):
     """Test a single version."""
-    self.assertEqual(self.best, uprev_lib.best_chrome_version([self.best]))
+    self.assertEqual(self.best, uprev_lib.best_version([self.best]))
 
   def test_multiple_versions(self):
     """Test a single version."""
-    self.assertEqual(self.best, uprev_lib.best_chrome_version(self.versions))
+    self.assertEqual(self.best, uprev_lib.best_version(self.versions))
 
   def test_no_versions_fail(self):
     """Test no versions given."""
-    with self.assertRaises(AssertionError):
-      uprev_lib.best_chrome_version([])
+    with self.assertRaises(TypeError):
+      uprev_lib.best_version([])
 
   def test_unstable_only(self):
     """Test the unstable version."""
     self.assertEqual(self.unstable,
-                     uprev_lib.best_chrome_version([self.unstable]))
+                     uprev_lib.best_version([self.unstable]))
 
   def test_unstable_multiple(self):
     """Test unstable alongside multiple other versions."""
     self.assertEqual(self.unstable,
-                     uprev_lib.best_chrome_version(self.unstable_versions))
+                     uprev_lib.best_version(self.unstable_versions))
 
   def test_single_ref(self):
     """Test a single ref."""
     self.assertEqual(self.best,
-                     uprev_lib.get_chrome_version_from_refs([self.best_ref]))
+                     uprev_lib.get_version_from_refs([self.best_ref]))
 
   def test_multiple_refs(self):
     """Test multiple refs."""
     self.assertEqual(self.best,
-                     uprev_lib.get_chrome_version_from_refs(self.refs))
+                     uprev_lib.get_version_from_refs(self.refs))
 
   def test_no_refs_fail(self):
     """Test no versions given."""
-    with self.assertRaises(AssertionError):
-      uprev_lib.get_chrome_version_from_refs([])
+    with self.assertRaises(TypeError):
+      uprev_lib.get_version_from_refs([])
 
 
 class ChromeEbuildVersionTest(cros_test_lib.MockTempDirTestCase):
@@ -118,7 +118,7 @@
 
   def test_no_ebuilds(self):
     """Test error on no ebuilds provided."""
-    with self.assertRaises(AssertionError):
+    with self.assertRaises(TypeError):
       uprev_lib.best_chrome_ebuild([])
 
   def test_single_ebuild(self):
diff --git a/lib/uri_lib.py b/lib/uri_lib.py
index 21e05b5..0037ce5 100644
--- a/lib/uri_lib.py
+++ b/lib/uri_lib.py
@@ -265,11 +265,11 @@
   return _MILO_BUILD_URL % {'buildbucket_id': buildbucket_id}
 
 
-def ConstructDashboardUri(buildbot_master_name, builder_name, build_number):
+def ConstructDashboardUri(buildbot_primary_name, builder_name, build_number):
   """Return the dashboard (luci-milo) URL for this run
 
   Args:
-    buildbot_master_name: Name of buildbot master, e.g. chromeos
+    buildbot_primary_name: Name of buildbot primary, e.g. chromeos
     builder_name: Builder name on buildbot dashboard.
     build_number: Build number for this validation attempt.
 
@@ -279,7 +279,7 @@
   url_suffix = '%s/%s' % (builder_name, str(build_number))
   url_suffix = urllib.parse.quote(url_suffix)
   return os.path.join(
-      _LUCI_MILO_BUILDBOT_URL, buildbot_master_name, url_suffix)
+      _LUCI_MILO_BUILDBOT_URL, buildbot_primary_name, url_suffix)
 
 
 def ConstructLogDogUri(build_number, stage):
@@ -299,7 +299,7 @@
   """Return the dashboard (viceroy) URL for this run.
 
   Args:
-    build_id: CIDB id for the master build.
+    build_id: CIDB id for the primary build.
 
   Returns:
     The fully formed URI.
diff --git a/lib/uri_lib_unittest.py b/lib/uri_lib_unittest.py
index f7c8c71..d35ce43 100644
--- a/lib/uri_lib_unittest.py
+++ b/lib/uri_lib_unittest.py
@@ -139,8 +139,8 @@
 
   def testConstructDashboardUrl(self):
     """Test generating dashboard URIs."""
-    actual = uri_lib.ConstructDashboardUri('master', 'builder', 123)
-    expected = 'https://luci-milo.appspot.com/buildbot/master/builder/123'
+    actual = uri_lib.ConstructDashboardUri('main', 'builder', 123)
+    expected = 'https://luci-milo.appspot.com/buildbot/main/builder/123'
     self.assertEqual(actual, expected)
 
   def testConstructLogDogUri(self):
diff --git a/lib/workon_helper.py b/lib/workon_helper.py
index 1b07b49..d4c5349 100644
--- a/lib/workon_helper.py
+++ b/lib/workon_helper.py
@@ -223,7 +223,7 @@
     self._unmasked_symlink = os.path.join(
         profile, 'package.unmask', 'cros-workon')
     self._keywords_symlink = os.path.join(
-        profile, 'package.keywords', 'cros-workon')
+        profile, 'package.accept_keywords', 'cros-workon')
     self._masked_symlink = os.path.join(
         profile, 'package.mask', 'cros-workon')
 
@@ -263,7 +263,8 @@
       sysroot = sysroot_lib.Sysroot(self._sysroot)
       portdir_overlay = sysroot.GetStandardField('PORTDIR_OVERLAY')
       if portdir_overlay:
-        self._cached_overlays = portdir_overlay.strip().splitlines()
+        self._cached_overlays = [
+            x.strip() for x in portdir_overlay.splitlines()]
       else:
         # This command is exceptionally slow, and we don't expect the list of
         # overlays to change during the lifetime of WorkonHelper.
@@ -584,16 +585,16 @@
     Args:
       atoms: iterable of atoms to ensure are in the manifest.
     """
-    if git.ManifestCheckout.IsFullManifest(self._src_root):
-      # If we're a full manifest, there is nothing to do.
-      return
+    manifest = git.ManifestCheckout.Cached(self._src_root)
 
     should_repo_sync = False
-    for ebuild_path in self._AtomsToEbuilds(atoms):
+    ebuilds = portage_util.FindEbuildsForPackages(atoms, self._sysroot)
+    for ebuild_path in ebuilds.values():
       infos = portage_util.GetRepositoryForEbuild(ebuild_path, self._sysroot)
       for info in infos:
-        if not info.project:
+        if not info.project or manifest.FindCheckouts(info.project):
           continue
+
         cmd = ['loman', 'add', '--workon', info.project]
         cros_build_lib.run(cmd, print_cmd=False)
         should_repo_sync = True
@@ -676,8 +677,8 @@
     if not quiet:
       # Legacy scripts used single quotes in their output, and we carry on this
       # honorable tradition.
-      logging.info("Started working on '%s' for '%s'",
-                   ' '.join(new_atoms), self._system)
+      logging.notice("Started working on '%s' for '%s'", ' '.join(new_atoms),
+                     self._system)
 
   def StopWorkingOnPackages(self,
                             packages,
@@ -719,8 +720,8 @@
     if stopped_atoms and not quiet:
       # Legacy scripts used single quotes in their output, and we carry on this
       # honorable tradition.
-      logging.info("Stopped working on '%s' for '%s'",
-                   ' '.join(stopped_atoms), self._system)
+      logging.notice("Stopped working on '%s' for '%s'",
+                     ' '.join(stopped_atoms), self._system)
 
   def GetPackageInfo(self, packages, use_all=False, use_workon_only=False):
     """Get information about packages.
diff --git a/lib/workon_helper_unittest.py b/lib/workon_helper_unittest.py
index 08b0c0d..e956778 100644
--- a/lib/workon_helper_unittest.py
+++ b/lib/workon_helper_unittest.py
@@ -12,12 +12,12 @@
 from chromite.lib import cros_test_lib
 from chromite.lib import depgraph
 from chromite.lib import dependency_graph
-from chromite.lib import git
 from chromite.lib.parser import package_info
 from chromite.lib import portage_util
 from chromite.lib import sysroot_lib
 from chromite.lib import osutils
 from chromite.lib import workon_helper
+from chromite.lib import unittest_lib
 
 
 BOARD = 'this_is_a_board_name'
@@ -119,9 +119,11 @@
     self.PatchObject(
         portage_util.PortageDB, 'InstalledPackages',
         return_value=[InstalledPackageMock('sys-apps', 'versioned-package')])
-    # This basically turns off behavior related to adding repositories to
-    # minilayouts.
-    self.PatchObject(git.ManifestCheckout, 'IsFullManifest', return_value=True)
+    # Turn off behavior related to adding repositories to minilayouts.
+    # TODO(b/208444115): Add tests for the full workflow. Ideally will be able
+    #  to create a manifest and ebuilds usable with `ebuild info`.
+    self.PatchObject(workon_helper.WorkonHelper,
+                     '_AddProjectsToPartialManifests')
     self.PatchObject(
         portage_util, 'GetRepositoryForEbuild', return_value=(
             portage_util.RepositoryInfoTuple(srcdir=self._mock_srcdir,
@@ -161,6 +163,8 @@
     # Setup the sysroots.
     sysroot_lib.Sysroot(self._sysroot).WriteConfig(
         'ARCH="amd64"\nPORTDIR_OVERLAY="%s"' % overlay)
+    # make.conf needs to exist to correctly read back config.
+    unittest_lib.create_stub_make_conf(self._sysroot)
 
     # Create helpers for the host or board.
     return workon_helper.WorkonHelper(
diff --git a/lib/xbuddy/build_artifact.py b/lib/xbuddy/build_artifact.py
index a9a9b6a..8601f70 100644
--- a/lib/xbuddy/build_artifact.py
+++ b/lib/xbuddy/build_artifact.py
@@ -413,7 +413,8 @@
     """
     files = super().StagedFiles()
     if self._files_to_extract:
-      return [x for x in files if os.path.basename(x) in self._files_to_extract]
+      return [x for x in files
+              if os.path.relpath(x, self.install_dir) in self._files_to_extract]
     return files
 
   def _RunUnzip(self, list_only):
diff --git a/lib/xbuddy/build_artifact_unittest.py b/lib/xbuddy/build_artifact_unittest.py
index 234cfa9..114e2d2 100644
--- a/lib/xbuddy/build_artifact_unittest.py
+++ b/lib/xbuddy/build_artifact_unittest.py
@@ -137,7 +137,7 @@
     'autotest/test_suites/control.faft_bios_au_2',
     'autotest/test_suites/control.faft_lv1',
     'autotest/test_suites/control.av_webcam',
-    'autotest/test_suites/control.power_check',
+    'autotest/test_suites/control.power_sanity',
     'autotest/test_suites/control.wificell-pre-cq',
     'autotest/test_suites/control.hotrod',
     'autotest/test_suites/control.skylab_staging_test',
@@ -192,6 +192,7 @@
     'autotest/test_suites/control.cr50_stress',
     'autotest/test_suites/control.cellular_ota_tmobile',
     'autotest/test_suites/control.wifi_interop',
+    'autotest/test_suites/control.arc-unit-test',
     'autotest/test_suites/control.bluestreak-partners',
     'autotest/test_suites/control.chameleon_hdmi_unstable',
     'autotest/test_suites/control.graphics',
@@ -504,3 +505,17 @@
     self.assertExists(os.path.join(self.work_dir, artifact.marker_name))
     self.assertFalse(artifact.ArtifactStaged())
     self.assertNotExists(os.path.join(self.work_dir, artifact.marker_name))
+
+  @cros_test_lib.pytestmark_network_test
+  def testStagedFiles(self):
+    """Tests getting the staged files."""
+    files_to_extract = ['config.txt', 'boot_images/vmlinuz']
+    artifact = build_artifact.BundledArtifact(
+        build_artifact.IMAGE_FILE, self.work_dir, _VERSION,
+        files_to_extract=files_to_extract)
+    expected_extracted_files = [os.path.join(self.work_dir, filename)
+                                for filename in files_to_extract]
+    artifact.Process(self.dl, False)
+
+    self.assertTrue(artifact.ArtifactStaged())
+    self.assertEqual(artifact.StagedFiles(), expected_extracted_files)
diff --git a/licensing/licenses.py b/licensing/licenses.py
index 8a44327..9b03225 100644
--- a/licensing/licenses.py
+++ b/licensing/licenses.py
@@ -20,7 +20,7 @@
   cros_sdk
   export BOARD=x86-alex
   sudo rm -rf /build/$BOARD
-  cd ~/trunk/src/scripts
+  cd ~/chromiumos/src/scripts
   # If you wonder why we need to build Chromium OS just to run
   # `emerge -p -v virtual/target-os` on it, we don't.
   # However, later we run ebuild unpack, and this will apply patches and run
@@ -29,7 +29,7 @@
   # This will take about 10mn on a Z620.
   ./build_packages --board=$BOARD --nowithautotest --nowithtest --nowithdev \
                    --nowithfactory
-  cd ~/trunk/chromite/licensing
+  cd ~/chromiumos/chromite/licensing
   # This removes left over packages from an earlier build that could cause
   # conflicts.
   eclean-$BOARD packages
diff --git a/licensing/licenses_lib.py b/licensing/licenses_lib.py
index ee4d407..d06ef93 100644
--- a/licensing/licenses_lib.py
+++ b/licensing/licenses_lib.py
@@ -277,7 +277,7 @@
   with cros_build_lib.UnbufferedNamedTemporaryFile() as f:
     osutils.WriteFile(f.name, ebuild_env_tmpl % tmpl_env)
     env = osutils.SourceEnvironment(
-        f.name, whitelist=['LICENSE'], ifs=' ', multiline=True)
+        f.name, allowlist=['LICENSE'], ifs=' ', multiline=True)
 
   if not env.get('LICENSE'):
     raise ValueError('No LICENSE found in the ebuild.')
@@ -430,7 +430,7 @@
                     file_path)
       if os.path.exists(file_path):
         # Turn
-        # /../merlin/trunk/src/third_party/chromiumos-overlay/../dev-util/bsdiff
+        # /.../chromiumos/src/third_party/chromiumos-overlay/../dev-util/bsdiff
         # into
         # chromiumos-overlay/../dev-util/bsdiff
         short_dir_path = os.path.join(*file_path.rsplit(os.path.sep, 5)[1:])
@@ -1453,11 +1453,11 @@
     file_template = ReadUnknownEncodedFile(output_template)
     tainted_warning = ''
     if self.tainted_pkgs:
+      tained_pkg_lis = '\n'.join(f'  <li>{x}</li>' for x in self.tainted_pkgs)
       tainted_warning = (TAINTED_COMMENT_TAG + '\n' +
-            '<h1>Image is TAINTED due to the following packages:</h1>\n' +
-            '<ul style="font-size:large">\n' +
-            '\n'.join(f'  <li>{x}</li>' for x in self.tainted_pkgs) +
-            '\n</ul>\n')
+                         '<h1>Image is TAINTED due to the following ' +
+                         'packages:</h1>\n<ul style="font-size:large">\n' +
+                         tained_pkg_lis + '\n</ul>\n')
       for tainted_pkg in self.tainted_pkgs:
         logging.warning('Package %s is tainted', tainted_pkg)
       logging.warning('Image is tainted. See licensing docs to fix this: '
diff --git a/navbar.md b/navbar.md
index 45ed64d..9186c3d 100644
--- a/navbar.md
+++ b/navbar.md
@@ -1,6 +1,6 @@
 # Chromite: Chromium OS build code
 
-[logo]: https://chromium-review.googlesource.com/plugins/chromium-style/static/chromium_logo.png
+[logo]: https://chromium-review.googlesource.com/plugins/chromium-style/static/web/chromium_logo.png
 [home]: /README.md
 
 * [Home][home]
diff --git a/scripts/build_dlc.py b/scripts/build_dlc.py
index 8d81caa..5f68d2a 100644
--- a/scripts/build_dlc.py
+++ b/scripts/build_dlc.py
@@ -109,6 +109,16 @@
       action='store_true',
       help='Allow indirect mount file generation for DLC.')
   one_dlc.add_argument(
+      '--reserved',
+      default=False,
+      action='store_true',
+      help='Always reserve space for this DLC.')
+  one_dlc.add_argument(
+      '--critical-update',
+      default=False,
+      action='store_true',
+      help='Always update with the OS for this DLC.')
+  one_dlc.add_argument(
       '--build-package',
       default=False,
       action='store_true',
@@ -161,7 +171,8 @@
   else:
     per_dlc_req_args += ['sysroot', 'board']
     per_dlc_invalid_args += ['name', 'pre_allocated_blocks', 'version',
-                             'package', 'days_to_purge']
+                             'package', 'days_to_purge', 'reserved',
+                             'critical_update']
 
   ValidateArguments(parser, opts, per_dlc_req_args, per_dlc_invalid_args)
 
@@ -178,6 +189,8 @@
         preload=opts.preload,
         factory_install=opts.factory_install,
         mount_file_required=opts.mount_file_required,
+        reserved=opts.reserved,
+        critical_update=opts.critical_update,
         used_by=opts.used_by,
         days_to_purge=opts.days_to_purge,
         fullnamerev=opts.fullnamerev)
diff --git a/scripts/build_minios.py b/scripts/build_minios.py
index 6b87842..966a811 100644
--- a/scripts/build_minios.py
+++ b/scripts/build_minios.py
@@ -27,18 +27,24 @@
                       help='The path to keyset.',
                       default=constants.VBOOT_DEVKEYS_DIR)
   parser.add_argument('--public-key',
-                      help='Filename to the public key whose private part '\
+                      help='Filename to the public key whose private part '
                       'signed the keyblock.',
-                      default=constants.RECOVERY_PUBLIC_KEY )
+                      default=constants.RECOVERY_PUBLIC_KEY)
   parser.add_argument('--private-key',
-                      help='Filename to the private key whose public part is '\
+                      help='Filename to the private key whose public part is '
                       'baked into the keyblock.',
-                      default=constants.MINIOS_DATA_PRIVATE_KEY )
+                      default=constants.MINIOS_DATA_PRIVATE_KEY)
   parser.add_argument('--keyblock',
                       help='Filename to the kernel keyblock.',
                       default=constants.MINIOS_KEYBLOCK)
   parser.add_argument('--serial', type=str,
                       help='Serial port for the kernel console (e.g. printks)')
+  parser.add_argument('--mod-for-dev', action='store_true',
+                      help='Repack the MiniOS image with debug flags.')
+  parser.add_argument('--force-build', action='store_true',
+                      help='Force the kernel to be rebuilt when repacking with '
+                      'debug flags. Use with --mod-for-dev in case kernel is '
+                      'not already built or needs to be rebuilt.')
   return parser
 
 
@@ -48,8 +54,10 @@
   opts.Freeze()
 
   with tempfile.TemporaryDirectory() as work_dir:
+    build_kernel = opts.force_build if opts.mod_for_dev else True
     kernel = minios.CreateMiniOsKernelImage(opts.board, opts.version, work_dir,
                                             opts.keys_dir, opts.public_key,
                                             opts.private_key, opts.keyblock,
-                                            opts.serial)
+                                            opts.serial, build_kernel,
+                                            opts.mod_for_dev)
     minios.InsertMiniOsKernelImage(opts.image, kernel)
diff --git a/scripts/build_minios_unittest.py b/scripts/build_minios_unittest.py
index ebeed2f..9f08101 100644
--- a/scripts/build_minios_unittest.py
+++ b/scripts/build_minios_unittest.py
@@ -54,6 +54,8 @@
         constants.MINIOS_DATA_PRIVATE_KEY,
         constants.MINIOS_KEYBLOCK,
         None,
+        True,
+        False,
     )])
 
     self.assertEqual(self.insert_minios_mock.mock_calls, [mock.call(
@@ -82,6 +84,7 @@
         '--private-key', test_private_key,
         '--keyblock', test_keyblock,
         '--serial', test_serial,
+        '--force-build',
     ])
 
     self.assertEqual(self.create_minios_mock.mock_calls, [mock.call(
@@ -93,6 +96,73 @@
         test_private_key,
         test_keyblock,
         test_serial,
+        True,
+        False,
+    )])
+
+    self.assertEqual(self.insert_minios_mock.mock_calls, [mock.call(
+        test_image, self.create_minios_mock_return,
+    )])
+
+  def testModForDev(self):
+    """Test that default arguments of build_minios are formatted correct."""
+    test_board = 'test-board'
+    test_version = '0.0.0.0'
+    test_image = '/some/image/path'
+    build_minios.main([
+        # --board is a required argument.
+        '--board', test_board,
+        # --version is a required argument.
+        '--version', test_version,
+        # --image is a required argument.
+        '--image', test_image,
+        '--mod-for-dev',
+    ])
+
+    self.assertEqual(self.create_minios_mock.mock_calls, [mock.call(
+        test_board,
+        test_version,
+        self._tempdir,
+        constants.VBOOT_DEVKEYS_DIR,
+        constants.RECOVERY_PUBLIC_KEY,
+        constants.MINIOS_DATA_PRIVATE_KEY,
+        constants.MINIOS_KEYBLOCK,
+        None,
+        False,
+        True,
+    )])
+
+    self.assertEqual(self.insert_minios_mock.mock_calls, [mock.call(
+        test_image, self.create_minios_mock_return,
+    )])
+
+  def testModForDevWithForceBuild(self):
+    """Test that default arguments of build_minios are formatted correct."""
+    test_board = 'test-board'
+    test_version = '0.0.0.0'
+    test_image = '/some/image/path'
+    build_minios.main([
+        # --board is a required argument.
+        '--board', test_board,
+        # --version is a required argument.
+        '--version', test_version,
+        # --image is a required argument.
+        '--image', test_image,
+        '--mod-for-dev',
+        '--force-build',
+    ])
+
+    self.assertEqual(self.create_minios_mock.mock_calls, [mock.call(
+        test_board,
+        test_version,
+        self._tempdir,
+        constants.VBOOT_DEVKEYS_DIR,
+        constants.RECOVERY_PUBLIC_KEY,
+        constants.MINIOS_DATA_PRIVATE_KEY,
+        constants.MINIOS_KEYBLOCK,
+        None,
+        True,
+        True,
     )])
 
     self.assertEqual(self.insert_minios_mock.mock_calls, [mock.call(
diff --git a/scripts/build_packages.py b/scripts/build_packages.py
new file mode 100644
index 0000000..bd021ab
--- /dev/null
+++ b/scripts/build_packages.py
@@ -0,0 +1,42 @@
+# Copyright 2022 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""build_packages updates the set of binary packages needed by Chrome OS.
+
+The build_packages process cross compiles all packages that have been
+updated into the given sysroot and builds binary packages as a side-effect.
+The output packages will be used by the build_image script to create a
+bootable Chrome OS image.
+"""
+
+import logging
+import os
+import urllib.error
+import urllib.request
+
+from chromite.lib import commandline
+from chromite.lib import constants
+from chromite.lib import cros_build_lib
+
+
+def main(argv):
+  commandline.RunInsideChroot()
+
+  cmd = [
+      'bash',
+      os.path.join(constants.CROSUTILS_DIR, 'build_packages.sh'),
+      '--script-is-run-only-by-chromite-and-not-users'
+  ]
+  cmd.extend(argv)
+  try:
+    # TODO(b/187793559): Don't pass in print_cmd once we switch to argparse
+    cros_build_lib.dbg_run(cmd, print_cmd=False)
+  except cros_build_lib.RunCommandError as e:
+    try:
+      request = urllib.request.urlopen(
+          'https://chromiumos-status.appspot.com/current?format=raw')
+      logging.notice('Tree Status: %s', request.read().decode())
+    except urllib.error.HTTPError:
+      pass
+    cros_build_lib.Die(e)
diff --git a/scripts/chrome_chromeos_lkgm.py b/scripts/chrome_chromeos_lkgm.py
index 7df182c..a55276f 100644
--- a/scripts/chrome_chromeos_lkgm.py
+++ b/scripts/chrome_chromeos_lkgm.py
@@ -12,22 +12,21 @@
 
 import distutils.version  # pylint: disable=import-error,no-name-in-module
 import logging
-import os
 import urllib.parse
 
 from chromite.cbuildbot import manifest_version
-from chromite.lib import chrome_committer
 from chromite.lib import commandline
 from chromite.lib import constants
+from chromite.lib import cros_build_lib
 from chromite.lib import gerrit
-from chromite.lib import osutils
+from chromite.lib import gob_util
 
 
-class LKGMNotValid(chrome_committer.CommitError):
+class LKGMNotValid(Exception):
   """Raised if the LKGM version is unset or not newer than the current value."""
 
 
-class LKGMFileNotFound(chrome_committer.CommitError):
+class LKGMFileNotFound(Exception):
   """Raised if the LKGM file is not found."""
 
 
@@ -41,6 +40,7 @@
       'chromeos-betty-pi-arc-chrome',
       'chromeos-eve-chrome',
       'chromeos-kevin-chrome',
+      'chromeos-octopus-chrome',
       'lacros-amd64-generic-chrome',
   ]
   # Files needed in a local checkout to successfully update the LKGM. The OWNERS
@@ -53,15 +53,21 @@
       'tools/translation/TRANSLATION_OWNERS',
   ]
   # First line of the commit message for all LKGM CLs.
-  _COMMIT_MSG_HEADER = 'LKGM %(lkgm)s for chromeos.'
+  _COMMIT_MSG_HEADER = 'Automated Commit: LKGM %(lkgm)s for chromeos.'
 
-  def __init__(self, user_email, workdir, lkgm, dryrun=False,
-               buildbucket_id=None):
+  def __init__(self, lkgm, dryrun=False, buildbucket_id=None):
     self._dryrun = dryrun
     self._buildbucket_id = buildbucket_id
-    self._committer = chrome_committer.ChromeCommitter(user_email, workdir)
     self._gerrit_helper = gerrit.GetCrosExternal()
 
+    # We need to use the account used by the builder to upload git CLs when
+    # generating CLs.
+    self._user_email = None
+    if cros_build_lib.HostIsCIBuilder(golo_only=True):
+      self._user_email = 'chromeos-commit-bot@chromium.org'
+    elif cros_build_lib.HostIsCIBuilder(gce_only=True):
+      self._user_email = '3su6n15k.default@developer.gserviceaccount.com'
+
     # Strip any chrome branch from the lkgm version.
     self._lkgm = manifest_version.VersionInfo(lkgm).VersionString()
     self._commit_msg_header = self._COMMIT_MSG_HEADER % {'lkgm': self._lkgm}
@@ -77,15 +83,7 @@
     if already_open_lkgm_cl:
       self.SubmitToCQ(already_open_lkgm_cl)
     else:
-      self._committer.Cleanup()
-      self._committer.Checkout(self._NEEDED_FILES)
       self.UpdateLKGM()
-      self.CommitNewLKGM()
-      self._committer.Upload()
-
-  def CheckoutChrome(self):
-    """Checks out chrome into tmp checkout_dir."""
-    self._committer.Checkout(self._NEEDED_FILES)
 
   @property
   def lkgm_file(self):
@@ -106,7 +104,7 @@
         # Use 'owner' rather than 'uploader' or 'author' since those last two
         # can be overwritten when the gardener resolves a merge-conflict and
         # uploads a new patchset.
-        'owner': self._committer.author,
+        'owner': self._user_email,
     }
     open_issues = self._gerrit_helper.Query(**query_params)
     if not open_issues:
@@ -146,7 +144,7 @@
         # Use 'owner' rather than 'uploader' or 'author' since those last two
         # can be overwritten when the gardener resolves a merge-conflict and
         # uploads a new patchset.
-        'owner': self._committer.author,
+        'owner': self._user_email,
         # The value of the LKGM is included in the first line of the commit
         # message. So including that in our query should only return CLs that
         # roll to our LKGM.
@@ -165,15 +163,19 @@
       logging.info('Would have applied CQ+2 to %s', already_open_lkgm_cl)
     else:
       logging.info('Applying CQ+2 to %s', already_open_lkgm_cl)
-      self._gerrit_helper.SetReview(already_open_lkgm_cl, labels=labels)
+      msg = None
+      if self._buildbucket_id:
+        msg = 'Applying CQ+2 from build %s' % self._buildbucket_id
+      self._gerrit_helper.SetReview(
+          already_open_lkgm_cl, labels=labels,
+          reviewers=[constants.CHROME_GARDENER_REVIEW_EMAIL],
+          msg=msg, ready=True)
 
   def UpdateLKGM(self):
     """Updates the LKGM file with the new version."""
-    lkgm_file = self.lkgm_file
-    if not os.path.exists(lkgm_file):
-      raise LKGMFileNotFound('%s is an invalid file' % lkgm_file)
-
-    self._old_lkgm = osutils.ReadFile(lkgm_file)
+    self._old_lkgm = gob_util.GetFileContentsOnHead(
+        constants.CHROMIUM_GOB_URL, 'chromeos/CHROMEOS_LKGM')
+    self._old_lkgm = self._old_lkgm.strip()
 
     lv = distutils.version.LooseVersion
     if self._old_lkgm is not None and lv(self._lkgm) <= lv(self._old_lkgm):
@@ -183,13 +185,27 @@
 
     logging.info('Updating LKGM version: %s (was %s),',
                  self._lkgm, self._old_lkgm)
-    osutils.WriteFile(lkgm_file, self._lkgm)
+    change = self._gerrit_helper.CreateChange(
+        'chromium/src', 'main', self.ComposeCommitMsg(), False)
+    self._gerrit_helper.ChangeEdit(
+        change.gerrit_number, 'chromeos/CHROMEOS_LKGM', self._lkgm)
+
+    # Apply Bot-Commit here to minimise the gap between uploading the
+    # CL and approving it.
+    labels = {'Bot-Commit': 1}
+    logging.info('Applying Bot-Commit+1')
+    self._gerrit_helper.SetReview(change.gerrit_number, labels=labels,
+                                  notify='NONE')
+    self._gerrit_helper.SetHashtags(change.gerrit_number, ['chrome-lkgm'], [])
 
   def ComposeCommitMsg(self):
     """Constructs and returns the commit message for the LKGM update."""
     commit_msg_template = (
         '%(header)s\n'
         '%(build_link)s'
+        '\nThis CL will remain in WIP until both master-full and '
+        'master-release\nbuilds for this version are finished. This CL '
+        'should not be submitted\nto the CQ until that happens.\n'
         '\n%(cq_includes)s')
     cq_includes = ''
     for bot in self._PRESUBMIT_BOTS:
@@ -202,11 +218,6 @@
         header=self._commit_msg_header, cq_includes=cq_includes,
         build_link=build_link)
 
-  def CommitNewLKGM(self):
-    """Commits the new LKGM file using our template commit message."""
-    self._committer.Commit([constants.PATH_TO_CHROME_LKGM],
-                           self.ComposeCommitMsg())
-
 
 def GetOpts(argv):
   """Returns a dictionary of parsed options.
@@ -217,10 +228,9 @@
   Returns:
     Dictionary of parsed options.
   """
-  committer_parser = chrome_committer.ChromeCommitter.GetParser()
-  parser = commandline.ArgumentParser(description=__doc__,
-                                      parents=[committer_parser],
-                                      add_help=False, logging=False)
+  parser = commandline.ArgumentParser(description=__doc__, add_help=False)
+  parser.add_argument('--dryrun', action='store_true', default=False,
+                      help="Don't commit changes or send out emails.")
   parser.add_argument('--lkgm', required=True,
                       help='LKGM version to update to.')
   parser.add_argument('--buildbucket-id',
@@ -228,9 +238,9 @@
                            'Will be linked in the commit message if specified.')
   return parser.parse_args(argv)
 
+
 def main(argv):
   opts = GetOpts(argv)
-  committer = ChromeLKGMCommitter(opts.user_email, opts.workdir,
-                                  opts.lkgm, opts.dryrun, opts.buildbucket_id)
+  committer = ChromeLKGMCommitter(opts.lkgm, opts.dryrun, opts.buildbucket_id)
   committer.Run()
   return 0
diff --git a/scripts/chrome_chromeos_lkgm_unittest.py b/scripts/chrome_chromeos_lkgm_unittest.py
index 1d52f95..3a328e1 100644
--- a/scripts/chrome_chromeos_lkgm_unittest.py
+++ b/scripts/chrome_chromeos_lkgm_unittest.py
@@ -4,14 +4,10 @@
 
 """Unit tests for the chrome_chromeos_lkgm program."""
 
-import os
 from unittest import mock
 import urllib.parse
 
-from chromite.lib import constants
 from chromite.lib import cros_test_lib
-from chromite.lib import osutils
-from chromite.lib import partial_mock
 from chromite.scripts import chrome_chromeos_lkgm
 
 
@@ -22,82 +18,62 @@
 
   def setUp(self):
     """Common set up method for all tests."""
-    self.committer = chrome_chromeos_lkgm.ChromeLKGMCommitter(
-        'user@test.org', self.tempdir, '1001.0.0')
-    self.lkgm_file = os.path.join(self.tempdir, constants.PATH_TO_CHROME_LKGM)
+    self.committer = chrome_chromeos_lkgm.ChromeLKGMCommitter('1001.0.0')
     self.old_lkgm = None
 
-  def _createOldLkgm(self, *args, **kwargs):  # pylint: disable=unused-argument
-    # Write out an old lkgm file as if we got it from a git fetch.
-    osutils.SafeMakedirs(os.path.join(self.tempdir, '.git', 'info'))
-    osutils.SafeMakedirs(os.path.dirname(self.lkgm_file))
-    osutils.WriteFile(self.lkgm_file, self.old_lkgm)
-
-  def testCheckoutChromeLKGM(self):
-    """Tests that we can read/obtain the old LKGM from mocked out git."""
-    self.old_lkgm = '1234.0.0'
-    self.rc.AddCmdResult(partial_mock.In('remote'), returncode=0,
-                         side_effect=self._createOldLkgm)
-    self.committer.CheckoutChrome()
-
-    self.assertEqual(self.committer.lkgm_file, self.lkgm_file)
-    self.assertEqual(osutils.ReadFile(self.lkgm_file), self.old_lkgm)
-
-  def testCommitNewLKGM(self):
+  @mock.patch('chromite.lib.gob_util.GetFileContentsOnHead')
+  def testCommitNewLKGM(self, mock_get_file):
     """Tests that we can commit a new LKGM file."""
-    self.old_lkgm = '999.0.0'
-    self.rc.AddCmdResult(partial_mock.In('remote'), returncode=0,
-                         side_effect=self._createOldLkgm)
-    self.committer.CheckoutChrome()
+    mock_get_file.return_value = '999.0.0'
+    with mock.patch.object(self.committer._gerrit_helper, 'CreateChange') as cg:
+      cg.return_value = mock.MagicMock(gerrit_number=123456)
+      with mock.patch.object(self.committer._gerrit_helper, 'ChangeEdit') as ce:
+        with mock.patch.object(
+            self.committer._gerrit_helper, 'SetReview') as bc:
+          with mock.patch.object(self.committer._gerrit_helper, 'SetHashtags'):
+            self.committer.UpdateLKGM()
+            ce.assert_called_once_with(123456, 'chromeos/CHROMEOS_LKGM',
+                                       '1001.0.0')
+            bc.assert_called_once_with(123456, labels={'Bot-Commit': 1},
+                                       notify='NONE')
 
-    self.assertEqual(self.committer.lkgm_file, self.lkgm_file)
-
-    self.committer.UpdateLKGM()
-    self.committer.CommitNewLKGM()
-
-    # Check the file was actually written out correctly.
-    self.assertEqual(osutils.ReadFile(self.lkgm_file), self.committer._lkgm)
-    self.assertCommandContains(['git', 'commit'])
-    self.assertEqual(self.committer._old_lkgm, self.old_lkgm)
-
-  def testOlderLKGMFails(self):
+  @mock.patch('chromite.lib.gob_util.GetFileContentsOnHead')
+  def testOlderLKGMFails(self, mock_get_file):
     """Tests that trying to update to an older lkgm version fails."""
-    self.old_lkgm = '1002.0.0'
-    self.rc.AddCmdResult(partial_mock.In('remote'), returncode=0,
-                         side_effect=self._createOldLkgm)
+    mock_get_file.return_value = '1002.0.0'
+    with mock.patch.object(self.committer._gerrit_helper, 'CreateChange') as cg:
+      cg.return_value = mock.MagicMock(gerrit_number=123456)
+      with mock.patch.object(self.committer._gerrit_helper, 'ChangeEdit') as ce:
+        self.assertRaises(chrome_chromeos_lkgm.LKGMNotValid,
+                          self.committer.UpdateLKGM)
+        ce.assert_not_called()
 
-    self.committer.CheckoutChrome()
-
-    self.assertRaises(chrome_chromeos_lkgm.LKGMNotValid,
-                      self.committer.UpdateLKGM)
-    self.assertEqual(self.committer._old_lkgm, self.old_lkgm)
-    self.assertEqual(self.committer._lkgm, '1001.0.0')
-    self.assertEqual(osutils.ReadFile(self.lkgm_file), '1002.0.0')
-
-  def testVersionWithChromeBranch(self):
+  @mock.patch('chromite.lib.gob_util.GetFileContentsOnHead')
+  def testVersionWithChromeBranch(self, mock_get_file):
     """Tests passing a version with a chrome branch strips the branch."""
-    self.committer = chrome_chromeos_lkgm.ChromeLKGMCommitter(
-        'user@test.org', self.tempdir, '1003.0.0-rc2')
+    self.committer = chrome_chromeos_lkgm.ChromeLKGMCommitter('1003.0.0-rc2')
+    mock_get_file.return_value = '1002.0.0'
 
-    self.old_lkgm = '1002.0.0'
-    self.rc.AddCmdResult(partial_mock.In('remote'), returncode=0,
-                         side_effect=self._createOldLkgm)
-
-    self.committer.CheckoutChrome()
-    self.committer.UpdateLKGM()
-    self.committer.CommitNewLKGM()
-
-    # Check the file was actually written out correctly.
-    stripped_lkgm = '1003.0.0'
-    self.assertEqual(osutils.ReadFile(self.lkgm_file), stripped_lkgm)
-    self.assertEqual(self.committer._old_lkgm, self.old_lkgm)
+    with mock.patch.object(self.committer._gerrit_helper, 'CreateChange') as cg:
+      cg.return_value = mock.MagicMock(gerrit_number=123456)
+      with mock.patch.object(self.committer._gerrit_helper, 'ChangeEdit') as ce:
+        with mock.patch.object(
+            self.committer._gerrit_helper, 'SetReview') as bc:
+          with mock.patch.object(self.committer._gerrit_helper, 'SetHashtags'):
+            # Check the file was actually written out correctly.
+            self.committer.UpdateLKGM()
+            ce.assert_called_once_with(123456, 'chromeos/CHROMEOS_LKGM',
+                                       '1003.0.0')
+            bc.assert_called_once_with(123456, labels={'Bot-Commit': 1},
+                                       notify='NONE')
 
   def testCommitMsg(self):
     """Tests format of the commit message."""
     self.committer._PRESUBMIT_BOTS = ['bot1', 'bot2']
     self.committer._buildbucket_id = 'some-build-id'
     commit_msg_lines = self.committer.ComposeCommitMsg().splitlines()
-    self.assertIn('LKGM 1001.0.0 for chromeos.', commit_msg_lines)
+    self.assertIn(
+        'Automated Commit: LKGM 1001.0.0 for chromeos.', commit_msg_lines)
     self.assertIn(
         'Uploaded by https://ci.chromium.org/b/some-build-id', commit_msg_lines)
     self.assertIn('CQ_INCLUDE_TRYBOTS=luci.chrome.try:bot1', commit_msg_lines)
@@ -126,6 +102,10 @@
           self.committer.FindAlreadyOpenLKGMRoll)
 
   def testSubmitToCQ(self):
+    self.committer._buildbucket_id = 'some-build-id'
     already_open_issue = 123456
-    with mock.patch.object(self.committer._gerrit_helper, 'SetReview'):
+    with mock.patch.object(
+        self.committer._gerrit_helper, 'SetReview') as mock_review:
       self.committer.SubmitToCQ(already_open_issue)
+    self.assertIn(
+        self.committer._buildbucket_id, mock_review.call_args[1]['msg'])
diff --git a/scripts/cros.py b/scripts/cros.py
index 34f2d68..5530157 100644
--- a/scripts/cros.py
+++ b/scripts/cros.py
@@ -85,7 +85,9 @@
     # import the single subcommand.
     parser = GetOptions(namespace.subcommand)
     namespace = parser.parse_args(argv)
+    namespace.command_class.ProcessOptions(parser, namespace)
     subcommand = namespace.command_class(namespace)
+    namespace.Freeze()
     try:
       code = _RunSubCommand(subcommand)
     except (commandline.ChrootRequiredError, commandline.ExecRequiredError):
diff --git a/scripts/cros_check_patches.py b/scripts/cros_check_patches.py
deleted file mode 100644
index 96d9b00..0000000
--- a/scripts/cros_check_patches.py
+++ /dev/null
@@ -1,238 +0,0 @@
-# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Command to list patches applies to a repository."""
-
-import functools
-import json
-import os
-import re
-import shutil
-import sys
-import tempfile
-
-from chromite.lib import cros_build_lib
-from chromite.lib import depgraph
-from chromite.lib import osutils
-from chromite.lib.parser import package_info
-
-
-class PatchReporter(object):
-  """Help discover patches being applied by ebuilds.
-
-  The patches can be compared to a set of expected patches.  They can also be
-  sorted into categories like 'needs_upstreaming', etc.  Use of this can help
-  ensure that critical (e.g. security) patches are not inadvertently dropped,
-  and help surface forgotten-about patches that are yet-to-be upstreamed.
-  """
-
-  PATCH_TYPES = ('upstreamed', 'needs_upstreaming', 'not_for_upstream',
-                 'uncategorized')
-
-  def __init__(self, config, overlay_dir, ebuild_cmd, equery_cmd, sudo=False):
-    """Initialize.
-
-    The 'config' dictionary should look like this:
-    {
-      "ignored_packages": ["chromeos-base/chromeos-chrome"],
-      "upstreamed": [],
-      "needs_upstreaming": [],
-      "not_for_upstream": [],
-      "uncategorized": [
-        "net-misc/htpdate htpdate-1.0.4-checkagainstbuildtime.patch",
-        "net-misc/htpdate htpdate-1.0.4-errorcheckhttpresp.patch"
-      ]
-    }
-    """
-    self.overlay_dir = os.path.realpath(overlay_dir)
-    self.ebuild_cmd = ebuild_cmd
-    self.equery_cmd = equery_cmd
-    self._invoke_command = cros_build_lib.run
-    if sudo:
-      self._invoke_command = functools.partial(cros_build_lib.sudo_run,
-                                               strict=False)
-    self.ignored_packages = config['ignored_packages']
-    self.package_count = 0
-    # The config format is stored as category: [ list of patches ]
-    # for ease of maintenance. But it's actually more useful to us
-    # in the code if kept as a map of patch:patch_type.
-    self.patches = {}
-    for cat in self.PATCH_TYPES:
-      for patch in config[cat]:
-        self.patches[patch] = cat
-
-  def Ignored(self, package_name):
-    """See if |package_name| should be ignored.
-
-    Args:
-      package_name: A package name (e.g. 'chromeos-base/chromeos-chrome')
-
-    Returns:
-      True if this package should be skipped in the analysis. False otherwise.
-    """
-    return package_name in self.ignored_packages
-
-  def ObservePatches(self, deps_map):
-    """Observe the patches being applied by ebuilds in |deps_map|.
-
-    Args:
-      deps_map: The packages to analyze.
-
-    Returns:
-      A list of patches being applied.
-    """
-    original = os.environ.get('PORT_LOGDIR', None)
-    temp_space = None
-    try:
-      temp_space = tempfile.mkdtemp(prefix='check_patches')
-      os.environ['PORT_LOGDIR'] = temp_space
-      return self._ObservePatches(temp_space, deps_map)
-    finally:
-      if temp_space:
-        shutil.rmtree(os.environ['PORT_LOGDIR'])
-      if original:
-        os.environ['PORT_LOGDIR'] = original
-      else:
-        os.environ.pop('PORT_LOGDIR')
-
-  def _ObservePatches(self, temp_space, deps_map):
-    for cpv in deps_map:
-      split = package_info.SplitCPV(cpv)
-      if self.Ignored(split.cp):
-        continue
-      cmd = self.equery_cmd[:]
-      cmd.extend(['which', cpv])
-      ebuild_path = self._invoke_command(cmd, print_cmd=False,
-                                         stdout=True).output.rstrip()
-      # Some of these packages will be from other portdirs. Since we are
-      # only interested in extracting the patches from one particular
-      # overlay, we skip ebuilds not from that overlay.
-      if self.overlay_dir != os.path.commonprefix([self.overlay_dir,
-                                                   ebuild_path]):
-        continue
-
-      # By running 'ebuild blah.ebuild prepare', we get logs in PORT_LOGDIR
-      # of what patches were applied. We clean first, to ensure we get a
-      # complete log, and clean again afterwards to avoid leaving a mess.
-      cmd = self.ebuild_cmd[:]
-      cmd.extend([ebuild_path, 'clean', 'prepare', 'clean'])
-      self._invoke_command(cmd, print_cmd=False, stdout=True)
-      self.package_count += 1
-
-    # Done with ebuild. Now just harvest the logs and we're finished.
-    # This regex is tuned intentionally to ignore a few unhelpful cases.
-    # E.g. elibtoolize repetitively applies a set of sed/portage related
-    # patches. And media-libs/jpeg says it is applying
-    # "various patches (bugfixes/updates)", which isn't very useful for us.
-    # So, if you noticed these omissions, it was intentional, not a bug. :-)
-    patch_regex = r'^ [*] Applying ([^ ]*) [.][.][.].*'
-    output = cros_build_lib.run(
-        ['egrep', '-r', patch_regex, temp_space], print_cmd=False,
-        stdout=True).output
-    lines = output.splitlines()
-    patches = []
-    patch_regex = re.compile(patch_regex)
-    for line in lines:
-      cat, pv, _, patchmsg = line.split(':')
-      cat = os.path.basename(cat)
-      split = package_info.SplitCPV('%s/%s' % (cat, pv))
-      patch_name = re.sub(patch_regex, r'\1', patchmsg)
-      patches.append('%s/%s %s' % (cat, split.package, patch_name))
-
-    return patches
-
-  def ReportDiffs(self, observed_patches):
-    """Prints a report on any differences to stdout.
-
-    Returns:
-      An int representing the total number of discrepancies found.
-    """
-    expected_patches = set(self.patches)
-    observed_patches = set(observed_patches)
-    missing_patches = sorted(list(expected_patches - observed_patches))
-    unexpected_patches = sorted(list(observed_patches - expected_patches))
-
-    if missing_patches:
-      print('Missing Patches:')
-      for p in missing_patches:
-        print('%s (%s)' % (p, self.patches[p]))
-
-    if unexpected_patches:
-      print('Unexpected Patches:')
-      print('\n'.join(unexpected_patches))
-
-    return len(missing_patches) + len(unexpected_patches)
-
-
-def Usage():
-  """Print usage."""
-  print("""Usage:
-cros_check_patches [--board=BOARD] [emerge args] package overlay-dir config.json
-
-Given a package name (e.g. 'virtual/target-os') and an overlay directory
-(e.g. /usr/local/portage/chromiumos), outputs a list of patches
-applied by that overlay, in the course of building the specified
-package and all its dependencies. Additional configuration options are
-specified in the JSON-format config file named on the command line.
-
-First run? Try this for a starter config:
-{
-  "ignored_packages": ["chromeos-base/chromeos-chrome"],
-  "upstreamed": [],
-  "needs_upstreaming": [],
-  "not_for_upstream": [],
-  "uncategorized": []
-}
-""")
-
-
-def main(argv):
-  if len(argv) < 4:
-    Usage()
-    sys.exit(1)
-
-  # Avoid parsing most of argv because most of it is destined for
-  # DepGraphGenerator/emerge rather than us. Extract what we need
-  # without disturbing the rest.
-  config_path = argv.pop()
-  config = json.loads(osutils.ReadFile(config_path))
-  overlay_dir = argv.pop()
-  board = [x.split('=')[1] for x in argv if x.find('--board=') != -1]
-  if board:
-    ebuild_cmd = ['ebuild-%s' % board[0]]
-    equery_cmd = ['equery-%s' % board[0]]
-  else:
-    ebuild_cmd = ['ebuild']
-    equery_cmd = ['equery']
-
-  use_sudo = not board
-
-  # We want the toolchain to be quiet to avoid interfering with our output.
-  depgraph_argv = ['--quiet', '--pretend', '--emptytree']
-
-  # Defaults to rdeps, but allow command-line override.
-  default_rootdeps_arg = ['--root-deps=rdeps']
-  for arg in argv:
-    if arg.startswith('--root-deps'):
-      default_rootdeps_arg = []
-
-  # Now, assemble the overall argv as the concatenation of the
-  # default list + possible rootdeps-default + actual command line.
-  depgraph_argv.extend(default_rootdeps_arg)
-  depgraph_argv.extend(argv)
-
-  deps = depgraph.DepGraphGenerator()
-  deps.Initialize(depgraph_argv)
-  deps_tree, deps_info, _ = deps.GenDependencyTree()
-  deps_map = deps.GenDependencyGraph(deps_tree, deps_info)
-
-  reporter = PatchReporter(config, overlay_dir, ebuild_cmd, equery_cmd,
-                           sudo=use_sudo)
-  observed = reporter.ObservePatches(deps_map)
-  diff_count = reporter.ReportDiffs(observed)
-
-  print('Packages analyzed: %d' % reporter.package_count)
-  print('Patches observed: %d' % len(observed))
-  print('Patches expected: %d' % len(reporter.patches))
-  sys.exit(diff_count)
diff --git a/scripts/cros_choose_profile_unittest.py b/scripts/cros_choose_profile_unittest.py
index 959448e..35c57ec 100644
--- a/scripts/cros_choose_profile_unittest.py
+++ b/scripts/cros_choose_profile_unittest.py
@@ -9,6 +9,7 @@
 from chromite.lib import commandline
 from chromite.lib import cros_test_lib
 from chromite.lib import osutils
+from chromite.lib import unittest_lib
 from chromite.scripts import cros_choose_profile
 
 
@@ -127,6 +128,9 @@
     for filepath, contents in path_contents.items():
       osutils.WriteFile(self._TempdirPath(filepath), contents)
 
+    # make.conf needs to exist to correctly read back config.
+    unittest_lib.create_stub_make_conf(self._TempdirPath(b1_build_root))
+
     # Mapping between profile argument and the expected parent contents.
     self.profile_expected_parent = {
         'base': path_contents[base_parent],
diff --git a/scripts/cros_env_whitelist.py b/scripts/cros_env_whitelist.py
index e8c2e7e..2fecb61 100644
--- a/scripts/cros_env_whitelist.py
+++ b/scripts/cros_env_whitelist.py
@@ -2,10 +2,14 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-"""Print the environment whitelist."""
+"""Print the environment allowlist."""
+
+import sys
 
 from chromite.lib import constants
 
 
-def main(_argv):
-  print(' '.join(constants.CHROOT_ENVIRONMENT_WHITELIST))
+def main(argv):
+  if argv:
+    sys.exit(f'{sys.argv[0]}: {__doc__}')
+  print(' '.join(constants.CHROOT_ENVIRONMENT_ALLOWLIST))
diff --git a/scripts/cros_fuzz.py b/scripts/cros_fuzz.py
index d3a5973..9198234 100644
--- a/scripts/cros_fuzz.py
+++ b/scripts/cros_fuzz.py
@@ -406,7 +406,9 @@
     extra_options = {}
 
   # log_path must be set because Chrome OS's patched compiler changes it.
-  options_dict = {'log_path': 'stderr'}
+  # disable odr violation since many fuzzers hit it and it is also disabled on
+  # clusterfuzz.
+  options_dict = {'log_path': 'stderr', 'detect_odr_violation': '0'}
   options_dict.update(extra_options)
   sanitizer_options = ':'.join('%s=%s' % x for x in options_dict.items())
   sanitizers = ('ASAN', 'MSAN', 'UBSAN')
@@ -553,7 +555,7 @@
   """
   with open(binary_path, 'rb') as file_handle:
     elf_file = ELFFile(file_handle)
-    return elf_file.get_section_by_name('__llvm_covmap') is not None
+    return elf_file.get_section_by_name(b'__llvm_covmap') is not None
 
 
 def RunFuzzerAndGenerateCoverageReport(fuzzer, corpus, fuzz_args):
diff --git a/scripts/cros_fuzz_unittest.py b/scripts/cros_fuzz_unittest.py
index f9e9886..a9b4184 100644
--- a/scripts/cros_fuzz_unittest.py
+++ b/scripts/cros_fuzz_unittest.py
@@ -176,9 +176,9 @@
         cros_fuzz.GetFuzzerSysrootPath(FUZZ_TARGET).sysroot,
     ]
     self.expected_extra_env = {
-        'ASAN_OPTIONS': 'log_path=stderr',
-        'MSAN_OPTIONS': 'log_path=stderr',
-        'UBSAN_OPTIONS': 'log_path=stderr',
+        'ASAN_OPTIONS': 'log_path=stderr:detect_odr_violation=0',
+        'MSAN_OPTIONS': 'log_path=stderr:detect_odr_violation=0',
+        'UBSAN_OPTIONS': 'log_path=stderr:detect_odr_violation=0',
     }
 
   def _Helper(self):
diff --git a/scripts/cros_gdb.py b/scripts/cros_gdb.py
index 9d735d6..fb615e7 100644
--- a/scripts/cros_gdb.py
+++ b/scripts/cros_gdb.py
@@ -147,7 +147,7 @@
     return sysroot
 
   def GetSimpleChromeBinary(self):
-    """Get path to the  binary in simple chrome."""
+    """Get path to the binary in simple chrome."""
     if self.binary:
       return self.binary
 
@@ -163,7 +163,7 @@
           else:
             raise GdbSimpleChromeBinaryError(
                 'There are multiple %s under %s. Please specify the path to '
-                'the binary via --binary'% binary_name, output_dir)
+                'the binary via --binary' % (binary_name, output_dir))
     if target_binary is None:
       raise GdbSimpleChromeBinaryError('There is no %s under %s.'
                                        % (binary_name, output_dir))
diff --git a/scripts/cros_generate_android_breakpad_symbols.py b/scripts/cros_generate_android_breakpad_symbols.py
index 32018b7..dcd33af 100644
--- a/scripts/cros_generate_android_breakpad_symbols.py
+++ b/scripts/cros_generate_android_breakpad_symbols.py
@@ -167,7 +167,7 @@
   osutils.SafeMakedirs(breakpad_dir)
   logging.info('generating breakpad symbols from %s', symbols_dir)
 
-  num_errors = multiprocessing.Value('i')
+  num_errors = parallel.WrapMultiprocessing(multiprocessing.Value, 'i')
 
   # Now start generating symbols for the discovered elfs.
   with parallel.BackgroundTaskRunner(
diff --git a/scripts/cros_generate_breakpad_symbols.py b/scripts/cros_generate_breakpad_symbols.py
index 151255c..c47c76c 100644
--- a/scripts/cros_generate_breakpad_symbols.py
+++ b/scripts/cros_generate_breakpad_symbols.py
@@ -262,7 +262,7 @@
 
       targets.append((os.path.getsize(debug_file), elf_file, debug_file))
 
-  bg_errors = multiprocessing.Value('i')
+  bg_errors = parallel.WrapMultiprocessing(multiprocessing.Value, 'i')
   if file_filter:
     files_not_found = [x for x, found in file_filter.items() if not found]
     bg_errors.value += len(files_not_found)
diff --git a/scripts/cros_generate_quick_provision_payload.py b/scripts/cros_generate_quick_provision_payload.py
new file mode 100644
index 0000000..0d535f7
--- /dev/null
+++ b/scripts/cros_generate_quick_provision_payload.py
@@ -0,0 +1,74 @@
+# Copyright 2022 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Script to generate Chromium OS quick provision payloads."""
+
+import os
+
+from chromite.lib import commandline
+from chromite.lib import constants
+from chromite.lib import cros_build_lib
+from chromite.lib import osutils
+from chromite.lib import parallel
+from chromite.lib.paygen import partition_lib
+from chromite.lib.paygen import paygen_stateful_payload_lib
+
+
+def ParseArguments(argv):
+  """Returns a namespace for the CLI arguments."""
+  parser = commandline.ArgumentParser(description=__doc__)
+  parser.add_argument('--image', type='path', required=True,
+                      help='The path to local image to build the quick '
+                      'provision payloads for.')
+  parser.add_argument('--output', type='path',
+                      help='The output directory to generate quick '
+                      'provision payloads for.', default='.')
+
+  opts = parser.parse_args(argv)
+  # Check if output is valid directory.
+  if not os.path.isdir(opts.output):
+    parser.error('Please pass in a valid output directory.')
+
+  opts.Freeze()
+
+  return opts
+
+
+def CreateKernelQuickProvisionPayload(image, output):
+  with osutils.TempDir() as temp_dir:
+    # Extract kernel.
+    kern = os.path.join(temp_dir, 'kern')
+    partition_lib.ExtractKernel(image, os.path.join(temp_dir, kern))
+     # Compress kernel.
+    cros_build_lib.CompressFile(
+        kern,
+        os.path.join(output, constants.QUICK_PROVISION_PAYLOAD_KERNEL))
+
+
+def CreateRootQuickProvisionPayload(image, output):
+  with osutils.TempDir() as temp_dir:
+    # Extract root.
+    root = os.path.join(temp_dir, 'root')
+    partition_lib.ExtractRoot(image, os.path.join(temp_dir, root))
+    # Compress root.
+    cros_build_lib.CompressFile(
+        root,
+        os.path.join(output, constants.QUICK_PROVISION_PAYLOAD_ROOTFS))
+
+
+def CreateStatefulQuickProvisionPayload(image, output):
+  # Create stateful quick provision payload.
+  paygen_stateful_payload_lib.GenerateStatefulPayload(image, output)
+  # Change output ownership of file.
+
+
+def main(argv):
+  opts = ParseArguments(argv)
+
+  parallel.RunParallelSteps([
+      # Stateful generation is usually the slowest.
+      lambda: CreateStatefulQuickProvisionPayload(opts.image, opts.output),
+      lambda: CreateKernelQuickProvisionPayload(opts.image, opts.output),
+      lambda: CreateRootQuickProvisionPayload(opts.image, opts.output),
+  ])
diff --git a/scripts/cros_generate_sysroot.py b/scripts/cros_generate_sysroot.py
index 4bd0303..60af9c2 100644
--- a/scripts/cros_generate_sysroot.py
+++ b/scripts/cros_generate_sysroot.py
@@ -70,10 +70,19 @@
     kwargs.setdefault('extra_env', self.extra_env)
     cros_build_lib.sudo_run(cmd, **kwargs)
 
+  def _WriteConfig(self, sysroot):
+    sysroot.WriteConfig(sysroot.GenerateBoardSetupConfig(self.options.board))
+    # For the config to be correctly read, a stub make.conf is needed.
+    # pylint: disable=protected-access
+    make_conf_path = os.path.join(self.sysroot, sysroot_lib._MAKE_CONF)
+    assert not os.path.exists(make_conf_path), 'Expecting an empty sysroot.'
+    osutils.WriteFile(os.path.join(make_conf_path),
+                      'source make.conf.board_setup', makedirs=True, sudo=True)
+
   def _InstallToolchain(self):
     # Create the sysroot's config.
     sysroot = sysroot_lib.Sysroot(self.sysroot)
-    sysroot.WriteConfig(sysroot.GenerateBoardSetupConfig(self.options.board))
+    self._WriteConfig(sysroot)
     toolchain.InstallToolchain(sysroot, configure=False)
 
   def _InstallKernelHeaders(self):
diff --git a/scripts/cros_list_modified_packages.py b/scripts/cros_list_modified_packages.py
index a390ff4..bee3c3a 100644
--- a/scripts/cros_list_modified_packages.py
+++ b/scripts/cros_list_modified_packages.py
@@ -126,7 +126,7 @@
   if sysroot.path == '/':
     overlays = portage_util.FindOverlays(constants.BOTH_OVERLAYS, None)
   else:
-    overlays = sysroot.GetStandardField('PORTDIR_OVERLAY').splitlines()
+    overlays = sysroot.portdir_overlay
 
   vdb_path = os.path.join(sysroot.path, portage_util.VDB_PATH)
 
diff --git a/scripts/cros_mark_android_as_stable.py b/scripts/cros_mark_android_as_stable.py
index 3034710..757cae7 100644
--- a/scripts/cros_mark_android_as_stable.py
+++ b/scripts/cros_mark_android_as_stable.py
@@ -4,15 +4,15 @@
 
 """This module uprevs Android for cbuildbot.
 
-After calling, it prints outs ANDROID_VERSION_ATOM=(version atom string).  A
-caller could then use this atom with emerge to build the newly uprevved version
-of Android e.g.
+After calling, it prints out a JSON representing the result, with the new
+Android version atom string included. A caller could then use this atom with
+emerge to build the newly uprevved version of Android e.g.
 
 ./cros_mark_android_as_stable \
     --android_build_branch=git_pi-arc \
     --android_package=android-container-pi
 
-Returns chromeos-base/android-container-pi-6417892-r1
+Returns {"android_atom": "chromeos-base/android-container-pi-6417892-r1"}
 
 emerge-eve =chromeos-base/android-container-pi-6417892-r1
 """
@@ -46,6 +46,18 @@
 TEST=CQ
 """
 
+_GIT_COMMIT_MESSAGE_LKGB = """%(android_package)s: Mark version \
+%(android_version)s as LKGB.
+
+Generated by Android PFQ. This change will trigger PUpr to actually submit an
+Android uprev.
+
+For details, see "Migration plan" section of go/android-uprev-recipes.
+
+BUG=None
+TEST=CQ
+"""
+
 _RUNTIME_ARTIFACTS_BUCKET_URL = 'gs://chromeos-arc-images/runtime_artifacts'
 
 
@@ -276,8 +288,8 @@
     msg = 'Previous ebuild with same version found and ebuild is redundant.'
     logging.info(msg)
     cbuildbot_alerts.PrintBuildbotStepText('%s %s not revved'
-                                  % (stable_candidate.pkgname,
-                                     stable_candidate.version))
+                                           % (stable_candidate.pkgname,
+                                              stable_candidate.version))
     osutils.SafeUnlink(new_ebuild_path)
     return None
 
@@ -294,7 +306,7 @@
   # Update ebuild manifest and git add it.
   gen_manifest_cmd = ['ebuild', new_ebuild_path, 'manifest', '--force']
   cros_build_lib.run(gen_manifest_cmd, extra_env=None, print_cmd=True)
-  files_to_add.append('Manifest')
+  files_to_add.append(os.path.join(package_dir, 'Manifest'))
 
   return (
       f'{new_ebuild.package}-{new_ebuild.version}',
@@ -322,7 +334,8 @@
 def _CommitChange(message, android_package_dir, files_to_add, files_to_remove):
   """Commit changes to git with list of files to add/remove."""
   git.RunGit(android_package_dir, ['add', '--'] + files_to_add)
-  git.RunGit(android_package_dir, ['rm', '--'] + files_to_remove)
+  if files_to_remove:
+    git.RunGit(android_package_dir, ['rm', '--'] + files_to_remove)
 
   portage_util.EBuild.CommitChange(message, android_package_dir)
 
@@ -347,7 +360,7 @@
   parser.add_argument('-f', '--force_version',
                       help='Android build id to use')
   parser.add_argument('-s', '--srcroot',
-                      default=os.path.join(os.environ['HOME'], 'trunk', 'src'),
+                      default=os.path.join(constants.SOURCE_ROOT, 'src'),
                       help='Path to the src directory')
   parser.add_argument('--runtime_artifacts_bucket_url',
                       default=_RUNTIME_ARTIFACTS_BUCKET_URL,
@@ -355,6 +368,11 @@
   parser.add_argument('--skip_commit',
                       action='store_true',
                       help='Skip commiting uprev changes to git')
+  parser.add_argument('--update_lkgb',
+                      action='store_true',
+                      help=('Update the LKGB file instead of uprevving ebuilds '
+                            'and populating artifacts. '
+                            'Requires --force_version be set.'))
   return parser
 
 
@@ -365,9 +383,50 @@
   options.Freeze()
 
   overlay_dir = os.path.abspath(_OVERLAY_DIR % {'srcroot': options.srcroot})
-  android_package_dir = os.path.join(
-      overlay_dir,
-      portage_util.GetFullAndroidPortagePackageName(options.android_package))
+  android_package_dir = android.GetAndroidPackageDir(options.android_package,
+                                                     overlay_dir=overlay_dir)
+
+  if not options.skip_commit:
+    _PrepareGitBranch(overlay_dir)
+
+  if options.update_lkgb:
+    if not options.force_version:
+      raise Exception('--force_version is required with --update_lkgb')
+
+    # Attempt to read current LKGB, if available.
+    current_lkgb = None
+    try:
+      current_lkgb = android.ReadLKGB(android_package_dir)
+    except android.MissingLKGBError:
+      logging.info('LKGB file is missing, creating a new one.')
+    except android.InvalidLKGBError:
+      logging.warning('Current LKGB file is invalid, overwriting.')
+
+    # Do nothing if LKGB is already set to the requested version.
+    if current_lkgb == options.force_version:
+      logging.warning('LKGB of %s is already %s, doing nothing.',
+                      options.android_package, options.force_version)
+      cbuildbot_alerts.PrintBuildbotStepText(
+          'LKGB of %s unchanged @ %s' % (options.android_package,
+                                         options.force_version))
+      return
+
+    # Actually update the LKGB.
+    path = android.WriteLKGB(android_package_dir, options.force_version)
+    cbuildbot_alerts.PrintBuildbotStepText(
+        'LKGB of %s updated %s -> %s' % (options.android_package,
+                                         current_lkgb, options.force_version))
+
+    if not options.skip_commit:
+      _CommitChange(
+          _GIT_COMMIT_MESSAGE_LKGB % {
+              'android_package': options.android_package,
+              'android_version': options.force_version},
+          android_package_dir,
+          [path],
+          [],
+      )
+    return
 
   # Use default Android branch if not overridden.
   android_build_branch = (
@@ -389,16 +448,15 @@
   else:
     logging.info('No stable candidate found.')
 
-  if not options.skip_commit:
-    _PrepareGitBranch(overlay_dir)
-
   revved = MarkAndroidEBuildAsStable(
       stable_candidate, unstable_ebuild, options.android_package,
       version_to_uprev, android_package_dir, android_build_branch,
       options.arc_bucket_url, options.runtime_artifacts_bucket_url)
 
+  output = dict(revved=bool(revved))
+
   if revved:
-    android_version_atom, files_to_add, files_to_remove = revved
+    android_atom, files_to_add, files_to_remove = revved
     if not options.skip_commit:
       _CommitChange(
           _GIT_COMMIT_MESSAGE % {'android_package': options.android_package,
@@ -410,7 +468,18 @@
     if options.boards:
       cros_mark_as_stable.CleanStalePackages(options.srcroot,
                                              options.boards.split(':'),
-                                             [android_version_atom])
+                                             [android_atom])
 
-    # Explicit print to communicate to caller.
-    print('ANDROID_VERSION_ATOM=%s' % android_version_atom)
+    output['android_atom'] = android_atom
+    # This field is read by the PUpr uprev handler for creating CLs. We cannot
+    # return absolute paths because this script runs inside chroot but the uprev
+    # handler runs outside.
+    # Here we return paths relative to |overlay_dir|.
+    output['modified_files'] = [os.path.relpath(f, overlay_dir)
+                                for f in files_to_add + files_to_remove]
+
+  # The output is being parsed by service.packages.uprev_android and has to be
+  # in its own single line. When invoked from chromite API endpoints, entering
+  # chroot can generate junk messages on stdout, so we prefix our output with a
+  # line break to further ensure that.
+  print('\n' + json.dumps(output, sort_keys=True))
diff --git a/scripts/cros_mark_android_as_stable_unittest.py b/scripts/cros_mark_android_as_stable_unittest.py
index 27efd04..0a17c95 100644
--- a/scripts/cros_mark_android_as_stable_unittest.py
+++ b/scripts/cros_mark_android_as_stable_unittest.py
@@ -4,6 +4,7 @@
 
 """Unit tests for cros_mark_android_as_stable.py."""
 
+import builtins
 import os
 
 from chromite.lib import constants
@@ -14,6 +15,7 @@
 from chromite.lib import osutils
 from chromite.lib import portage_util
 from chromite.scripts import cros_mark_android_as_stable
+from chromite.service import android
 
 pytestmark = cros_test_lib.pytestmark_inside_only
 
@@ -40,18 +42,18 @@
     """Setup vars and create mock dir."""
     self.android_package = constants.ANDROID_PI_PACKAGE
 
-    self.tmp_overlay = os.path.join(self.tempdir, 'chromiumos-overlay')
-    self.mock_android_dir = os.path.join(
-        self.tmp_overlay,
-        portage_util.GetFullAndroidPortagePackageName(self.android_package))
+    self.tmp_overlay = os.path.join(self.tempdir, 'private-overlays',
+                                    'project-cheets-private')
+    self.mock_android_dir = android.GetAndroidPackageDir(
+        self.android_package, overlay_dir=self.tmp_overlay)
 
     ebuild = os.path.join(self.mock_android_dir,
                           self.android_package + '-%s.ebuild')
     self.unstable = ebuild % '9999'
     self.old_version = '25'
-    self.old = ebuild % self.old_version
+    self.old = ebuild % ('%s-r1' % self.old_version)
     self.old2_version = '50'
-    self.old2 = ebuild % self.old2_version
+    self.old2 = ebuild % ('%s-r1' % self.old2_version)
     self.new_version = '100'
     self.new = ebuild % ('%s-r1' % self.new_version)
 
@@ -116,11 +118,10 @@
     version_atom, files_to_add, files_to_remove = revved
     self.assertEqual(
         version_atom,
-        '%s-%s-r1' % (
-            portage_util.GetFullAndroidPortagePackageName(self.android_package),
-            self.new_version))
-    self.assertEqual(files_to_add, [self.new, 'Manifest'])
-    self.assertEqual(files_to_remove, [])
+        f'chromeos-base/{self.android_package}-{self.new_version}-r1')
+    self.assertEqual(files_to_add,
+                     [self.new, os.path.join(package_dir, 'Manifest')])
+    self.assertEqual(files_to_remove, [self.old2])
 
   def testUpdateDataCollectorArtifacts(self):
     android_version = 100
@@ -189,3 +190,188 @@
         'X86_64_USER_UREADAHEAD_PACK': expectation1,
         'ARM_USERDEBUG_GMS_CORE_CACHE': expectation2,
     }, variables)
+
+  def testMainRevved(self):
+    android_version = self.new_version
+
+    self.PatchObject(cros_build_lib, 'run')
+    self.PatchObject(portage_util.EBuild, 'GetCrosWorkonVars',
+                     return_value=None)
+    self.setupMockRuntimeDataBuild(android_version)
+    mock_mirror_artifacts = self.PatchObject(android, 'MirrorArtifacts',
+                                             return_value=android_version)
+    mock_print = self.PatchObject(builtins, 'print')
+    android_bucket_url = 'gs://ab'
+
+    cros_mark_android_as_stable.main([
+        '--android_bucket_url', android_bucket_url,
+        '--android_build_branch', self.build_branch,
+        '--android_package', self.android_package,
+        '--arc_bucket_url', self.arc_bucket_url,
+        '--force_version', android_version,
+        '--srcroot', self.tempdir,
+        '--runtime_artifacts_bucket_url', self.runtime_artifacts_bucket_url,
+        '--skip_commit',
+    ])
+
+    mock_mirror_artifacts.assert_called_once_with(android_bucket_url,
+                                                  self.build_branch,
+                                                  self.arc_bucket_url,
+                                                  self.mock_android_dir,
+                                                  android_version)
+    # pylint: disable=line-too-long
+    mock_print.assert_called_once_with('\n{"android_atom": "chromeos-base/android-container-pi-100-r1", "modified_files": ["chromeos-base/android-container-pi/android-container-pi-100-r1.ebuild", "chromeos-base/android-container-pi/Manifest", "chromeos-base/android-container-pi/android-container-pi-50-r1.ebuild"], "revved": true}')
+
+  def testMainNotRevved(self):
+    android_version = self.old2_version
+
+    # Mock to create a stable ebuild identical to the original.
+    def MockMarkAsStable(_unstable_path, new_stable_path, _vars, **_kwargs):
+      osutils.WriteFile(new_stable_path, self.stable_data)
+
+    self.PatchObject(portage_util.EBuild, 'GetCrosWorkonVars',
+                     return_value=None)
+    self.PatchObject(portage_util.EBuild, 'MarkAsStable',
+                     side_effect=MockMarkAsStable)
+    self.setupMockRuntimeDataBuild(android_version)
+    mock_mirror_artifacts = self.PatchObject(android, 'MirrorArtifacts',
+                                             return_value=android_version)
+    mock_print = self.PatchObject(builtins, 'print')
+    android_bucket_url = 'gs://ab'
+
+    cros_mark_android_as_stable.main([
+        '--android_bucket_url', android_bucket_url,
+        '--android_build_branch', self.build_branch,
+        '--android_package', self.android_package,
+        '--arc_bucket_url', self.arc_bucket_url,
+        '--force_version', android_version,
+        '--srcroot', self.tempdir,
+        '--runtime_artifacts_bucket_url', self.runtime_artifacts_bucket_url,
+        '--skip_commit',
+    ])
+
+    mock_mirror_artifacts.assert_called_once_with(android_bucket_url,
+                                                  self.build_branch,
+                                                  self.arc_bucket_url,
+                                                  self.mock_android_dir,
+                                                  android_version)
+    mock_print.assert_called_once_with('\n{"revved": false}')
+
+  def testMainUpdateLKGB(self):
+    """Tests a successful LKGB update without an actual uprev."""
+    android_version = 'android-version'
+    old_version = 'old-version'
+
+    self.PatchObject(cros_mark_android_as_stable, '_PrepareGitBranch')
+    mock_commit = self.PatchObject(cros_mark_android_as_stable, '_CommitChange')
+    self.PatchObject(android, 'ReadLKGB', return_value=old_version)
+    mock_write_lkgb = self.PatchObject(android, 'WriteLKGB')
+    mock_mirror_artifacts = self.PatchObject(android, 'MirrorArtifacts')
+    mock_mark_as_stable = self.PatchObject(portage_util.EBuild, 'MarkAsStable')
+
+    cros_mark_android_as_stable.main([
+        '--android_package', self.android_package,
+        '--force_version', android_version,
+        '--srcroot', self.tempdir,
+        '--update_lkgb',
+    ])
+
+    mock_write_lkgb.assert_called_once_with(self.mock_android_dir,
+                                            android_version)
+    mock_commit.assert_called_once()
+    mock_mirror_artifacts.assert_not_called()
+    mock_mark_as_stable.assert_not_called()
+
+  def testMainUpdateLKGBMissingLKGB(self):
+    """Tests LKGB update when LKGB file is currently missing."""
+    android_version = 'android-version'
+
+    self.PatchObject(cros_mark_android_as_stable, '_PrepareGitBranch')
+    mock_commit = self.PatchObject(cros_mark_android_as_stable, '_CommitChange')
+    self.PatchObject(android, 'ReadLKGB',
+                     side_effect=android.MissingLKGBError())
+    mock_write_lkgb = self.PatchObject(android, 'WriteLKGB')
+
+    cros_mark_android_as_stable.main([
+        '--android_package', self.android_package,
+        '--force_version', android_version,
+        '--srcroot', self.tempdir,
+        '--update_lkgb',
+    ])
+
+    mock_write_lkgb.assert_called_once_with(self.mock_android_dir,
+                                            android_version)
+    mock_commit.assert_called_once()
+
+  def testMainUpdateLKGBInvalidLKGB(self):
+    """Tests LKGB update when current LKGB file is invalid."""
+    android_version = 'android-version'
+
+    self.PatchObject(cros_mark_android_as_stable, '_PrepareGitBranch')
+    mock_commit = self.PatchObject(cros_mark_android_as_stable, '_CommitChange')
+    self.PatchObject(android, 'ReadLKGB',
+                     side_effect=android.InvalidLKGBError())
+    mock_write_lkgb = self.PatchObject(android, 'WriteLKGB')
+
+    cros_mark_android_as_stable.main([
+        '--android_package', self.android_package,
+        '--force_version', android_version,
+        '--srcroot', self.tempdir,
+        '--update_lkgb',
+    ])
+
+    mock_write_lkgb.assert_called_once_with(self.mock_android_dir,
+                                            android_version)
+    mock_commit.assert_called_once()
+
+  def testMainUpdateLKGBNoUpdate(self):
+    """Tests if nothing happens when LKGB is left unchanged."""
+    android_version = 'old-version'
+    old_version = 'old-version'
+
+    self.PatchObject(cros_mark_android_as_stable, '_PrepareGitBranch')
+    mock_commit = self.PatchObject(cros_mark_android_as_stable, '_CommitChange')
+    self.PatchObject(android, 'ReadLKGB', return_value=old_version)
+    mock_write_lkgb = self.PatchObject(android, 'WriteLKGB')
+
+    cros_mark_android_as_stable.main([
+        '--android_package', self.android_package,
+        '--force_version', android_version,
+        '--srcroot', self.tempdir,
+        '--update_lkgb',
+    ])
+
+    mock_write_lkgb.assert_not_called()
+    mock_commit.assert_not_called()
+
+  def testMainUpdateLKGBWithoutVersion(self):
+    """Tests when --force_version flag is missing during LKGB update."""
+    self.PatchObject(cros_mark_android_as_stable, '_PrepareGitBranch')
+
+    with self.assertRaises(Exception):
+      cros_mark_android_as_stable.main([
+          '--android_package', self.android_package,
+          '--srcroot', self.tempdir,
+          '--update_lkgb',
+      ])
+
+  def testMainUpdateLKGBSkipCommit(self):
+    """Tests when --skip_commit is set during LKGB update."""
+    android_version = 'android-version'
+    old_version = 'old-version'
+
+    mock_commit = self.PatchObject(cros_mark_android_as_stable, '_CommitChange')
+    self.PatchObject(android, 'ReadLKGB', return_value=old_version)
+    mock_write_lkgb = self.PatchObject(android, 'WriteLKGB')
+
+    cros_mark_android_as_stable.main([
+        '--android_package', self.android_package,
+        '--force_version', android_version,
+        '--srcroot', self.tempdir,
+        '--skip_commit',
+        '--update_lkgb',
+    ])
+
+    mock_write_lkgb.assert_called_once_with(self.mock_android_dir,
+                                            android_version)
+    mock_commit.assert_not_called()
diff --git a/scripts/cros_portage_upgrade.py b/scripts/cros_portage_upgrade.py
index 4014dde..5065718 100644
--- a/scripts/cros_portage_upgrade.py
+++ b/scripts/cros_portage_upgrade.py
@@ -630,7 +630,7 @@
     # Expecting emerge_output to have lines like this:
     #  The following mask changes are necessary to proceed:
     # #required by ... =somecategory/somepackage (some reason)
-    # # /home/mtennant/trunk/src/third_party/chromiumos-overlay/profiles\
+    # # /.../chromiumos/src/third_party/chromiumos-overlay/profiles\
     # /targets/chromeos/package.mask:
     # >=upgraded_cp
     package_mask = None
@@ -977,23 +977,6 @@
       # Update profiles/categories.
       self._UpdateCategories(pinfo)
 
-      # Regenerate the cache.  In theory, this might glob too much, but
-      # in practice, this should be fine for now ...
-      cache_files = 'metadata/md5-cache/%s-[0-9]*' % pinfo.package
-      self._RunGit(self._stable_repo, ['rm', '--ignore-unmatch', '-q', '-f',
-                                       cache_files])
-      cmd = ['egencache', '--update', '--repo=portage-stable', pinfo.package]
-      egen_result = cros_build_lib.run(cmd, print_cmd=False,
-                                       stdout=True,
-                                       stderr=subprocess.STDOUT,
-                                       encoding='utf-8')
-      if egen_result.returncode != 0:
-        raise RuntimeError('Failed to regenerate md5-cache for %r.\n'
-                           'Output of %r:\n%s' %
-                           (pinfo.package, ' '.join(cmd), egen_result.output))
-
-      self._RunGit(self._stable_repo, ['add', cache_files])
-
     return bool(pinfo.upgraded_cpv)
 
   def _UpdateCategories(self, pinfo):
@@ -1804,7 +1787,7 @@
   parser.add_argument('--rdeps', action='store_true', default=False,
                       help='Use runtime dependencies only')
   parser.add_argument('--srcroot', type='path',
-                      default='%s/trunk/src' % os.environ['HOME'],
+                      default=os.path.join(constants.SOURCE_ROOT, 'src'),
                       help='Path to root src directory [default: %(default)s]')
   parser.add_argument('--to-csv', dest='csv_file', type='path',
                       default=None, help='File to store csv-formatted results')
diff --git a/scripts/cros_portage_upgrade_unittest.py b/scripts/cros_portage_upgrade_unittest.py
index 253883a..520800b 100644
--- a/scripts/cros_portage_upgrade_unittest.py
+++ b/scripts/cros_portage_upgrade_unittest.py
@@ -1922,12 +1922,6 @@
       cmdargs.append('--force')
     mocked_upgrader = self._MockUpgrader(cmdargs=cmdargs)
 
-    # Add test-specific mocks/stubs.
-    run_result = cros_build_lib.CommandResult(returncode=0)
-    run_mock = self.PatchObject(cros_build_lib, 'run',
-                                return_value=run_result)
-    run_calls = []
-
     # Replay script.
     def FindUpstreamCPV(pkg, unstable_ok=False):
       self.assertEqual(pinfo.package, pkg)
@@ -1950,23 +1944,13 @@
           ebuild_path = cpu.Upgrader._GetEbuildPathFromCpv(upstream_cpv)
           ebuild_path = os.path.join(mocked_upgrader._stable_repo,
                                      ebuild_path)
-          cache_files = 'metadata/md5-cache/%s-[0-9]*' % pinfo.package
           git_calls += [
               mock.call(mocked_upgrader._stable_repo, ['add', pinfo.package]),
-              mock.call(mocked_upgrader._stable_repo,
-                        ['rm', '--ignore-unmatch', '-q', '-f', cache_files]),
-              mock.call(mocked_upgrader._stable_repo, ['add', cache_files]),
           ]
-          cmd = ['egencache', '--update', '--repo=portage-stable',
-                 pinfo.package]
-          run_calls.append(mock.call(cmd, print_cmd=False, stdout=True,
-                                     stderr=subprocess.STDOUT,
-                                     encoding='utf-8'))
 
     # Verify.
     result = cpu.Upgrader._UpgradePackage(mocked_upgrader, pinfo)
 
-    run_mock.assert_has_calls(run_calls)
     mocked_upgrader._RunGit.assert_has_calls(git_calls)
 
     if upstream_cpv:
diff --git a/scripts/cros_run_unit_tests.py b/scripts/cros_run_unit_tests.py
index ab7afd3..c76de9e 100644
--- a/scripts/cros_run_unit_tests.py
+++ b/scripts/cros_run_unit_tests.py
@@ -24,6 +24,7 @@
                           constants.TARGET_OS_DEV_PKG,
                           constants.TARGET_OS_TEST_PKG,
                           constants.TARGET_OS_FACTORY_PKG)
+SDK_VIRTUAL_PACKAGES = (constants.TARGET_SDK,)
 IMPLICIT_TEST_DEPS = ('virtual/implicit-system',)
 
 
@@ -38,6 +39,8 @@
   target = parser.add_mutually_exclusive_group(required=True)
   target.add_argument('--sysroot', type='path', help='Path to the sysroot.')
   target.add_argument('--board', help='Board name.')
+  target.add_argument('--host', action='store_true',
+                      help='Run tests for the host SDK.')
 
   parser.add_argument('--pretend', default=False, action='store_true',
                       help='Show the list of packages to be tested and return.')
@@ -89,21 +92,29 @@
   return options
 
 
-def determine_board_packages(sysroot, virtual_packages):
+def determine_packages(sysroot, virtual_packages):
   """Returns a set of the dependencies for the given packages"""
   deps, _bdeps = cros_extract_deps.ExtractDeps(
       sysroot, virtual_packages, include_bdepend=False)
   return set(
       '%s/%s' % (atom['category'], atom['name']) for atom in deps.values())
 
+def get_keep_going():
+  """Check if should enable keep_going parameter.
+
+  If the 'USE' environment contains 'coverage' then enable keep_going option
+  to prevent certain package failure from breaking the whole coverage
+  generation workflow, otherwise leave it to default settings
+  """
+  return 'coverage' in os.environ.get('USE', '')
 
 def main(argv):
   opts = ParseArgs(argv)
 
   cros_build_lib.AssertInsideChroot()
 
-  sysroot = (opts.sysroot or
-             build_target_lib.get_default_sysroot_path(opts.board))
+  sysroot = (opts.sysroot or '/' if opts.host
+             else build_target_lib.get_default_sysroot_path(opts.board))
   skipped_packages = set()
   if opts.skip_packages:
     skipped_packages |= set(opts.skip_packages.split())
@@ -125,7 +136,8 @@
                 else set(workon.ListAtoms(use_all=True)))
 
   if opts.empty_sysroot:
-    packages |= determine_board_packages(sysroot, BOARD_VIRTUAL_PACKAGES)
+    packages |= determine_packages(sysroot, SDK_VIRTUAL_PACKAGES if opts.host
+                                   else BOARD_VIRTUAL_PACKAGES)
     workon = workon_helper.WorkonHelper(sysroot)
     workon_packages = set(workon.ListAtoms(use_all=True))
     packages &= workon_packages
@@ -158,6 +170,8 @@
     use_flags += ' -cros-debug'
     env['USE'] = use_flags
 
+  keep_going = get_keep_going()
+
   metrics_dir = os.environ.get(constants.CROS_METRICS_DIR_ENVVAR)
   if metrics_dir:
     env[constants.CROS_METRICS_DIR_ENVVAR] = metrics_dir
@@ -173,8 +187,8 @@
       return 1
 
   try:
-    chroot_util.RunUnittests(
-        sysroot, pkg_with_test, extra_env=env, jobs=opts.jobs)
+    chroot_util.RunUnittests(sysroot, pkg_with_test, extra_env=env,
+                             keep_going=keep_going, jobs=opts.jobs)
   except cros_build_lib.RunCommandError:
     logging.error('Unittests failed.')
     return 1
diff --git a/scripts/cros_run_unit_tests_unittest.py b/scripts/cros_run_unit_tests_unittest.py
index 5696729..9d773c9 100644
--- a/scripts/cros_run_unit_tests_unittest.py
+++ b/scripts/cros_run_unit_tests_unittest.py
@@ -4,6 +4,8 @@
 
 """Unit tests for cros_run_unit_tests.py."""
 
+import os
+
 from chromite.lib import cros_test_lib
 from chromite.scripts import cros_run_unit_tests
 
@@ -11,10 +13,16 @@
 pytestmark = cros_test_lib.pytestmark_inside_only
 
 
-class DetermineBoardPackagesTest(cros_test_lib.TestCase):
-  """Tests that package determination returns a non-empty set"""
+class CrosRunUnitTestsTest(cros_test_lib.MockTestCase):
+  """Tests for cros_run_unit_tests functions."""
 
   def testNonEmptyPackageSet(self):
     """Asserts that the deps of a known package are non-empty"""
-    self.assertTrue(cros_run_unit_tests.determine_board_packages(
+    self.assertTrue(cros_run_unit_tests.determine_packages(
         '/', ('virtual/implicit-system',)))
+
+  def testGetKeepGoing(self):
+    """Tests set keep_going option based on env virables"""
+    self.PatchObject(os, 'environ', new={'USE': 'chrome_internal coverage'})
+    keep_going = cros_run_unit_tests.get_keep_going()
+    self.assertEqual(keep_going, True)
diff --git a/scripts/cros_sdk.py b/scripts/cros_sdk.py
index 286354d..a904337 100644
--- a/scripts/cros_sdk.py
+++ b/scripts/cros_sdk.py
@@ -173,7 +173,8 @@
 
 
 def EnterChroot(chroot_path, cache_dir, chrome_root, chrome_root_mount,
-                goma_dir, goma_client_json, working_dir, additional_args):
+                goma_dir, goma_client_json, reclient_dir, reproxy_cfg_file,
+                working_dir, additional_args):
   """Enters an existing SDK chroot"""
   st = os.statvfs(os.path.join(chroot_path, 'usr', 'bin', 'sudo'))
   if st.f_flag & os.ST_NOSUID:
@@ -188,6 +189,10 @@
     cmd.extend(['--goma_dir', goma_dir])
   if goma_client_json:
     cmd.extend(['--goma_client_json', goma_client_json])
+  if reclient_dir:
+    cmd.extend(['--reclient_dir', reclient_dir])
+  if reproxy_cfg_file:
+    cmd.extend(['--reproxy_cfg_file', reproxy_cfg_file])
   if working_dir is not None:
     cmd.extend(['--working_dir', working_dir])
 
@@ -206,14 +211,7 @@
     logging.notice(
         'Raising vm.max_map_count from %s to %s', max_map_count, file_limit)
     open('/proc/sys/vm/max_map_count', 'w').write(f'{file_limit}\n')
-  ret = cros_build_lib.dbg_run(cmd, check=False)
-  # If we were in interactive mode, ignore the exit code; it'll be whatever
-  # they last ran w/in the chroot and won't matter to us one way or another.
-  # Note this does allow chroot entrance to fail and be ignored during
-  # interactive; this is however a rare case and the user will immediately
-  # see it (nor will they be checking the exit code manually).
-  if ret.returncode != 0 and additional_args:
-    raise SystemExit(ret.returncode)
+  return cros_build_lib.dbg_run(cmd, check=False)
 
 
 def _ImageFileForChroot(chroot):
@@ -421,10 +419,10 @@
 def _SudoCommand():
   """Get the 'sudo' command, along with all needed environment variables."""
 
-  # Pass in the ENVIRONMENT_WHITELIST and ENV_PASSTHRU variables so that
+  # Pass in the ENVIRONMENT_ALLOWLIST and ENV_PASSTHRU variables so that
   # scripts in the chroot know what variables to pass through.
   cmd = ['sudo']
-  for key in constants.CHROOT_ENVIRONMENT_WHITELIST + constants.ENV_PASSTHRU:
+  for key in constants.CHROOT_ENVIRONMENT_ALLOWLIST + constants.ENV_PASSTHRU:
     value = os.environ.get(key)
     if value is not None:
       cmd += ['%s=%s' % (key, value)]
@@ -703,6 +701,14 @@
       type='path',
       help='Service account json file to use goma on bot. '
       'Mounted into the chroot.')
+  parser.add_argument(
+      '--reclient-dir',
+      type='path',
+      help='Reclient installed directory to mount into the chroot.')
+  parser.add_argument(
+      '--reproxy-cfg-file',
+      type='path',
+      help="Config file for re-client's reproxy used for remoteexec.")
 
   # Use type=str instead of type='path' to prevent the given path from being
   # transfered to absolute path automatically.
@@ -1177,7 +1183,9 @@
       lock.read_lock()
       if not mounted:
         cros_sdk_lib.MountChrootPaths(options.chroot)
-      EnterChroot(options.chroot, options.cache_dir, options.chrome_root,
-                  options.chrome_root_mount, options.goma_dir,
-                  options.goma_client_json, options.working_dir,
-                  chroot_command)
+      ret = EnterChroot(options.chroot, options.cache_dir, options.chrome_root,
+                        options.chrome_root_mount, options.goma_dir,
+                        options.goma_client_json, options.reclient_dir,
+                        options.reproxy_cfg_file, options.working_dir,
+                        chroot_command)
+      sys.exit(ret.returncode)
diff --git a/scripts/cros_setup_toolchains.py b/scripts/cros_setup_toolchains.py
index 14825c1..a6762fe 100644
--- a/scripts/cros_setup_toolchains.py
+++ b/scripts/cros_setup_toolchains.py
@@ -69,6 +69,7 @@
     'dev-lang/rust-bootstrap',
     'virtual/target-sdk-post-cross',
     'dev-embedded/coreboot-sdk',
+    'dev-embedded/hps-sdk',
     'dev-embedded/ti50-sdk',
 )
 
@@ -100,6 +101,7 @@
     'armv7a-cros-linux-gnueabi',
     'armv7a-cros-linux-gnueabihf',
     'aarch64-cros-linux-gnu',
+    'i686-cros-linux-gnu',
     'i686-pc-linux-gnu',
     'x86_64-cros-linux-gnu',
 )
@@ -235,12 +237,36 @@
     """Calls crossdev to initialize a cross target.
 
     Args:
-      targets: The list of targets to initialize using crossdev.
+      targets: The dict of targets to initialize using crossdev.
       usepkg: Copies the commandline opts.
       config_only: Just update.
     """
     configured_targets = cls._CACHE.setdefault('configured_targets', [])
+    started_targets = set()
 
+    # Schedule all of the targets in parallel, and let them run.
+    with parallel.BackgroundTaskRunner(cls._UpdateTarget) as queue:
+      for target_name in targets:
+        # We already started this target in this loop.
+        if target_name in started_targets:
+          continue
+        # The target is already configured.
+        if config_only and target_name in configured_targets:
+          continue
+        queue.put([target_name, targets[target_name], usepkg, config_only])
+        started_targets.add(target_name)
+
+  @classmethod
+  def _UpdateTarget(cls, target_name, target, usepkg, config_only):
+    """Calls crossdev to initialize a cross target.
+
+    Args:
+      target_name: The name of the target to initialize.
+      target: The target info for initializing.
+      usepkg: Copies the commandline opts.
+      config_only: Just update.
+    """
+    configured_targets = cls._CACHE.setdefault('configured_targets', [])
     cmdbase = ['crossdev', '--show-fail-log']
     cmdbase.extend(['--env', 'FEATURES=splitdebug'])
     # Pick stable by default, and override as necessary.
@@ -254,43 +280,36 @@
     cmdbase.extend(['--overlays', overlays])
     cmdbase.extend(['--ov-output', CROSSDEV_OVERLAY])
 
-    # Build target by the reversed alphabetical order to make sure
-    # armv7a-cros-linux-gnueabihf builds before armv7a-cros-linux-gnueabi
-    # because some dependency issue. This can be reverted once we
-    # migrated to armv7a-cros-linux-gnueabihf. crbug.com/711369
-    for target in sorted(targets, reverse=True):
-      if config_only and target in configured_targets:
-        continue
+    cmd = cmdbase + ['-t', target_name]
 
-      cmd = cmdbase + ['-t', target]
-
-      for pkg in GetTargetPackages(target):
-        if pkg == 'gdb':
-          # Gdb does not have selectable versions.
-          cmd.append('--ex-gdb')
-        elif pkg == 'ex_compiler-rt':
-          cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
-        elif pkg == 'ex_go':
-          # Go does not have selectable versions.
-          cmd.extend(CROSSDEV_GO_ARGS)
-        elif pkg in LLVM_PKGS_TABLE:
-          cmd.extend(LLVM_PKGS_TABLE[pkg])
-        elif pkg in cls.MANUAL_PKGS:
-          pass
-        else:
-          # The first of the desired versions is the "primary" one.
-          version = GetDesiredPackageVersions(target, pkg)[0]
-          cmd.extend(['--%s' % pkg, version])
-
-      cmd.extend(targets[target]['crossdev'].split())
-      if config_only:
-        # In this case we want to just quietly reinit
-        cmd.append('--init-target')
-        cros_build_lib.run(cmd, print_cmd=False, stdout=True)
+    for pkg in GetTargetPackages(target_name):
+      if pkg == 'gdb':
+        # Gdb does not have selectable versions.
+        cmd.append('--ex-gdb')
+      elif pkg == 'ex_compiler-rt':
+        cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
+      elif pkg == 'ex_go':
+        # Go does not have selectable versions.
+        cmd.extend(CROSSDEV_GO_ARGS)
+      elif pkg in LLVM_PKGS_TABLE:
+        cmd.extend(LLVM_PKGS_TABLE[pkg])
+      elif pkg in cls.MANUAL_PKGS:
+        pass
       else:
-        cros_build_lib.run(cmd)
+        # The first of the desired versions is the "primary" one.
+        version = GetDesiredPackageVersions(target_name, pkg)[0]
+        cmd.extend(['--%s' % pkg, version])
 
-      configured_targets.append(target)
+    cmd.extend(target['crossdev'].split())
+
+    if config_only:
+      # In this case we want to just quietly reinit
+      cmd.append('--init-target')
+      cros_build_lib.run(cmd, print_cmd=False, stdout=True)
+    else:
+      cros_build_lib.run(cmd)
+
+    configured_targets.append(target_name)
 
 
 def GetTargetPackages(target):
@@ -347,7 +366,7 @@
   """Extracts the current stable version for a given package.
 
   Args:
-    atom: The target/package to operate on eg. i686-pc-linux-gnu,gcc
+    atom: The target/package to operate on e.g. i686-cros-linux-gnu/gcc
     installed: Whether we want installed packages or ebuilds
     root: The root to use when querying packages.
 
@@ -365,7 +384,7 @@
   Resolving means replacing PACKAGE_STABLE with the actual number.
 
   Args:
-    target: The target to operate on (e.g. i686-pc-linux-gnu)
+    target: The target to operate on (e.g. i686-cros-linux-gnu)
     package: The target/package to operate on (e.g. gcc)
     versions: List of versions to resolve
     installed: Query installed packages
@@ -398,7 +417,7 @@
   mean 'unstable' in most cases.
 
   Args:
-    target: The target to operate on (e.g. i686-pc-linux-gnu)
+    target: The target to operate on (e.g. i686-cros-linux-gnu)
     package: The target/package to operate on (e.g. gcc)
 
   Returns:
@@ -418,7 +437,7 @@
   preferred, because all packages can be updated in a single pass.
 
   Args:
-    target: The target to operate on (e.g. i686-pc-linux-gnu)
+    target: The target to operate on (e.g. i686-cros-linux-gnu)
 
   Returns:
     True if |target| is completely initialized, else False
@@ -443,7 +462,7 @@
   The pre-existing package.mask files can mess with the keywords.
 
   Args:
-    target: The target to operate on (e.g. i686-pc-linux-gnu)
+    target: The target to operate on (e.g. i686-cros-linux-gnu)
   """
   maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
   osutils.SafeUnlink(maskfile)
@@ -698,6 +717,12 @@
     # work on bare systems where this is useful.
     targets = ExpandTargets(targets_wanted)
 
+    # Filter out toolchains that don't (yet) have a binpkg available.
+    if usepkg:
+      for target in list(targets.keys()):
+        if not targets[target]['have-binpkg']:
+          del targets[target]
+
     # Now re-add any targets that might be from this board. This is to
     # allow unofficial boards to declare their own toolchains.
     for board in boards_wanted:
@@ -1176,6 +1201,31 @@
   osutils.SafeMakedirs(os.path.join(output_dir, 'usr', target, 'usr/lib'))
 
 
+def _CreateRemoteToolchainFile(output_dir):
+  """Create a remote_toolchain_inputs file for reclient/RBE"""
+  # The inputs file lists all files/shared libraries needed to run clang.
+  # All inputs are relative to location of clang binary and one input
+  # location per line of file e.g.
+  # clang-13.elf
+  # clang++-13.elf
+  # relative/path/to/clang/resource/directory
+
+  clang_path = os.path.join(output_dir, 'usr/bin')
+  # Add needed shared libraries and internal files e.g. allowlists.
+  toolchain_inputs = ['../../lib']
+  clang_shared_dirs = glob.glob(
+      os.path.join(output_dir, 'usr/lib64/clang/*/share'))
+  for clang_dir in clang_shared_dirs:
+    toolchain_inputs.append(os.path.relpath(clang_dir, clang_path))
+
+  # Add actual clang binaries/wrappers.
+  for clang_files in glob.glob(os.path.join(clang_path, 'clang*-[0-9]*')):
+    toolchain_inputs.append(os.path.basename(clang_files))
+
+  with open(os.path.join(clang_path, 'remote_toolchain_inputs'), 'w') as f:
+    f.writelines('%s\n' % line for line in toolchain_inputs)
+
+
 def _ProcessDistroCleanups(target, output_dir):
   """Clean up the tree and remove all distro-specific requirements
 
@@ -1188,6 +1238,7 @@
   _ProcessSysrootWrappers(target, output_dir, gcc_path)
   _ProcessClangWrappers(target, output_dir)
   _CreateMainLibDir(target, output_dir)
+  _CreateRemoteToolchainFile(output_dir)
 
   osutils.RmDir(os.path.join(output_dir, 'etc'))
 
diff --git a/scripts/cros_uprev.py b/scripts/cros_uprev.py
index 671ce68..b45c6a7 100644
--- a/scripts/cros_uprev.py
+++ b/scripts/cros_uprev.py
@@ -33,8 +33,8 @@
   parser.add_argument('--boards', help='Colon-separated list of boards.')
   parser.add_argument('--chroot', type='path', help='The chroot path.')
   parser.add_argument('--force', action='store_true',
-                      help='Force the stabilization of blacklisted packages. '
-                           '(only compatible with -p)')
+                      help='Force the stabilization of manually uprevved '
+                           'packages. (only compatible with -p)')
   parser.add_argument('--overlay-type', required=True,
                       choices=['public', 'private', 'both'],
                       help='Populates --overlays based on "public", "private", '
@@ -178,7 +178,7 @@
   Args:
     overlays: A list of overlays to work on.
     package_list: A list of packages passed from commandline to work on.
-    force (bool): Whether to use packages even if in blacklist.
+    force (bool): Whether to use packages even if in manual uprev list.
 
   Returns:
     A dict mapping each overlay to a list of ebuilds belonging to it.
diff --git a/scripts/crosfw.py b/scripts/crosfw.py
index c937d7a..8560fd8 100644
--- a/scripts/crosfw.py
+++ b/scripts/crosfw.py
@@ -89,13 +89,13 @@
 --verify --full-erase
 --bootcmd "cros_test sha"
 --gbb-flags -force-dev-switch-on
---bmpblk ~/trunk/src/third_party/u-boot/bmp.bin
+--bmpblk ~/chromiumos/src/third_party/u-boot/bmp.bin
 
 For example: -a "--gbb-flags -force-dev-switch-on"
 
 Note the standard bmpblk is at:
-  /home/$USER/trunk/src/third_party/chromiumos-overlay/sys-boot/
-      chromeos-bootimage/files/bmpblk.bin"
+  ~/chromiumos/src/third_party/chromiumos-overlay/sys-boot/
+      chromeos-bootimage/files/bmpblk.bin
 """
 
 import glob
diff --git a/scripts/deploy_chrome.py b/scripts/deploy_chrome.py
index b2434bd..7dffa2c 100644
--- a/scripts/deploy_chrome.py
+++ b/scripts/deploy_chrome.py
@@ -75,6 +75,7 @@
 LACROS_DIR = '/usr/local/lacros-chrome'
 _CONF_FILE = '/etc/chrome_dev.conf'
 _KILL_LACROS_CHROME_CMD = 'pkill -f %(lacros_dir)s/chrome'
+_RESET_LACROS_CHROME_CMD = 'rm -rf /home/chronos/user/lacros'
 MODIFIED_CONF_FILE = f'modified {_CONF_FILE}'
 
 # This command checks if "--enable-features=LacrosSupport" is present in
@@ -229,6 +230,10 @@
     self.device.run(_KILL_LACROS_CHROME_CMD %
                     {'lacros_dir': self.options.target_dir}, check=False)
 
+  def _ResetLacrosChrome(self):
+    """Reset Lacros to fresh state by deleting user data dir."""
+    self.device.run(_RESET_LACROS_CHROME_CMD, check=False)
+
   def _KillAshChromeIfNeeded(self):
     """This method kills ash-chrome on the device, if it's running.
 
@@ -477,6 +482,8 @@
       # If this is a lacros build, we only want to restart ash-chrome if needed.
       restart_ui = False
       steps.append(self._KillLacrosChrome)
+      if self.options.reset_lacros:
+        steps.append(self._ResetLacrosChrome)
       if self.options.modify_config_file:
         restart_ui = self._ModifyConfigFileIfNeededForLacros()
 
@@ -609,6 +616,9 @@
                            'binaries.' % _CHROME_TEST_BIN_DIR)
   parser.add_argument('--lacros', action='store_true', default=False,
                       help='Deploys lacros-chrome rather than ash-chrome.')
+  parser.add_argument('--reset-lacros', action='store_true', default=False,
+                      help='Reset Lacros by deleting Lacros user data dir if '
+                           'exists.')
   parser.add_argument('--skip-modifying-config-file', action='store_false',
                       dest='modify_config_file',
                       help='By default, deploying lacros-chrome modifies the '
diff --git a/scripts/gen_luci_scheduler.py b/scripts/gen_luci_scheduler.py
index f68912e..d91962d 100644
--- a/scripts/gen_luci_scheduler.py
+++ b/scripts/gen_luci_scheduler.py
@@ -106,7 +106,7 @@
   schedule: "%(schedule)s"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "%(builder)s"
 %(tag_lines)s
 %(prop_lines)s
diff --git a/scripts/gen_luci_scheduler_unittest.py b/scripts/gen_luci_scheduler_unittest.py
index 0f6f79e..e8fc4ad 100644
--- a/scripts/gen_luci_scheduler_unittest.py
+++ b/scripts/gen_luci_scheduler_unittest.py
@@ -37,7 +37,7 @@
   schedule: "funky schedule"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "LegacyRelease"
     tags: "cbb_branch:main"
     tags: "cbb_config:amd64-generic-release"
@@ -125,7 +125,7 @@
   schedule: "funky schedule"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "LegacyRelease"
     tags: "cbb_branch:mock_branch"
     tags: "cbb_config:amd64-generic-release"
@@ -156,7 +156,7 @@
   schedule: "funky schedule"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "LegacyRelease"
     tags: "cbb_branch:main"
     tags: "cbb_config:amd64-generic-release"
@@ -189,7 +189,7 @@
   schedule: "funky schedule"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "LegacyRelease"
     tags: "cbb_branch:main"
     tags: "cbb_config:amd64-generic-release"
@@ -343,7 +343,7 @@
   schedule: "run once in a while"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "ReleaseBuilder"
     tags: "cbb_branch:main"
     tags: "cbb_config:build_prod"
@@ -362,7 +362,7 @@
   schedule: "run daily"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "TestBuilder"
     tags: "cbb_branch:main"
     tags: "cbb_config:build_tester"
@@ -381,7 +381,7 @@
   schedule: "triggered"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "ReleaseBuilder"
     tags: "cbb_branch:main"
     tags: "cbb_config:build_triggered_a"
@@ -400,7 +400,7 @@
   schedule: "triggered"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "ProdBuilder"
     tags: "cbb_branch:main"
     tags: "cbb_config:build_triggered_b"
@@ -419,7 +419,7 @@
   schedule: "run daily"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "TestBuilder"
     tags: "cbb_branch:test-branch"
     tags: "cbb_config:branch_tester"
@@ -438,7 +438,7 @@
   schedule: "run daily"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromeos.general"
+    bucket: "general"
     builder: "TestBuilder"
     tags: "cbb_branch:test-branch"
     tags: "cbb_config:branch_tester_triggered"
diff --git a/scripts/generate_reclient_inputs.py b/scripts/generate_reclient_inputs.py
new file mode 100644
index 0000000..a477c47
--- /dev/null
+++ b/scripts/generate_reclient_inputs.py
@@ -0,0 +1,112 @@
+# Copyright 2022 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Creates a remote_toolchain_inputs file for Reclient.
+
+Reclient(go/rbe/dev/x/reclient) is used for remote execution of build
+actions in build systems e.g. Chrome. It needs a toolchain inputs file
+next to clang compiler binary which has all the input dependencies
+needed to run the clang binary remotely.
+
+Running the script:
+$ generate_reclient_inputs [--output file_name] [--clang /path/to/clang]
+will create the file /path/to/file_name.
+
+By default, the script will write to /usr/bin/remote_toolchain_inputs.
+
+Contact: Chrome OS toolchain team.
+"""
+
+import os
+from pathlib import Path
+from typing import List, Optional, Set
+
+from chromite.lib import commandline
+from chromite.lib import cros_build_lib
+from chromite.lib import osutils
+from chromite.third_party import lddtree
+
+
+def _GetSymLinkPath(base_dir: Path, link_path: str) -> Path:
+  """Return the actual symlink path relative to base directory."""
+  if not link_path:
+    return None
+  # Handle absolute symlink paths.
+  if link_path[0] == '/':
+    return link_path
+  # handle relative symlinks.
+  return base_dir / link_path
+
+
+def _CollectElfDeps(elfpath: Path) -> Set[Path]:
+  """Returns the set of dependent files for the elf file."""
+  libs = set()
+  to_process = [elfpath]
+  elf = lddtree.ParseELF(elfpath, ldpaths=lddtree.LoadLdpaths())
+  for _, lib_data in elf['libs'].items():
+    if lib_data['path']:
+      to_process.append(Path(lib_data['path']))
+
+  while to_process:
+    path = to_process.pop()
+    if not path or path in libs:
+      continue
+    libs.add(path)
+    if path.is_symlink():
+      # TODO: Replace os.readlink() by path.readlink().
+      to_process.append(_GetSymLinkPath(path.parent, os.readlink(path)))
+
+  return libs
+
+
+def _GenerateRemoteInputsFile(out_file: str, clang_path: Path) -> None:
+  """Generate Remote Inputs for Clang for executing on reclient/RBE."""
+  clang_dir = clang_path.parent
+  # Start with collecting shared library dependencies.
+  paths = _CollectElfDeps(clang_path)
+
+  # Clang is typically a symlink, collect actual files.
+  paths.add(clang_path)
+
+  # Add clang resources, gcc config and glibc loader files.
+  cmd = [str(clang_path), '--print-resource-dir']
+  resource_dir = cros_build_lib.run(
+      cmd, capture_output=True, encoding='utf-8',
+      print_cmd=False).stdout.splitlines()[0]
+  paths.add(Path(resource_dir) / 'share')
+  paths.update(
+      Path(x) for x in (
+          '/etc/env.d/gcc',
+          '/etc/ld.so.cache',
+          '/etc/ld.so.conf',
+          '/etc/ld.so.conf.d',
+      ))
+
+  # Write the files relative to clang binary location.
+  osutils.WriteFile(
+      clang_dir / out_file,
+      [os.path.relpath(x, clang_dir) + '\n' for x in sorted(paths)],
+      sudo=True)
+
+
+def ParseArgs(argv: Optional[List[str]]) -> commandline.argparse.Namespace:
+  """Parses program arguments."""
+  parser = commandline.ArgumentParser(description=__doc__)
+
+  parser.add_argument(
+      '--output',
+      default='remote_toolchain_inputs',
+      help='Name of remote toolchain file relative to clang binary directory.')
+  parser.add_argument(
+      '--clang', type=Path, default='/usr/bin/clang', help='Clang binary path.')
+
+  opts = parser.parse_args(argv)
+  opts.Freeze()
+  return opts
+
+
+def main(argv: Optional[List[str]] = None) -> Optional[int]:
+  cros_build_lib.AssertInsideChroot()
+  opts = ParseArgs(argv)
+  _GenerateRemoteInputsFile(opts.output, opts.clang)
diff --git a/scripts/gerrit.py b/scripts/gerrit.py
index aac14cb..5552b2f 100644
--- a/scripts/gerrit.py
+++ b/scripts/gerrit.py
@@ -684,6 +684,48 @@
                           dryrun=opts.dryrun, notify=opts.notify)
 
 
+class ActionAttentionSet(UserAction):
+  """Add/remove emails from the attention set (prepend with '~' to remove)"""
+
+  COMMAND = 'attention'
+
+  @staticmethod
+  def init_subparser(parser):
+    """Add arguments to this action's subparser."""
+    parser.add_argument('-m', '--msg', '--message', metavar='MESSAGE',
+                        help='Optional message to include',
+                        default='gerrit CLI')
+    parser.add_argument('cl', metavar='CL',
+                        help='The CL to update')
+    parser.add_argument('users', nargs='+',
+                        help='The users to add/remove from attention set')
+
+  @staticmethod
+  def __call__(opts):
+    """Implement the action."""
+    # Allow for optional leading '~'.
+    email_validator = re.compile(r'^[~]?%s$' % constants.EMAIL_REGEX)
+    add_list, remove_list, invalid_list = [], [], []
+
+    for email in opts.users:
+      if not email_validator.match(email):
+        invalid_list.append(email)
+      elif email[0] == '~':
+        remove_list.append(email[1:])
+      else:
+        add_list.append(email)
+
+    if invalid_list:
+      cros_build_lib.Die(
+          'Invalid email address(es): %s' % ', '.join(invalid_list))
+
+    if add_list or remove_list:
+      helper, cl = GetGerrit(opts, opts.cl)
+      helper.SetAttentionSet(cl, add=add_list, remove=remove_list,
+                             dryrun=opts.dryrun, notify=opts.notify,
+                             message=opts.msg)
+
+
 class ActionMessage(_ActionSimpleParallelCLs):
   """Add a message to a CL"""
 
@@ -1139,8 +1181,8 @@
                      help='Query internal Chrome Gerrit instance')
   group.add_argument('-g', '--gob',
                      default=site_params.EXTERNAL_GOB_INSTANCE,
-                     help='Gerrit (on borg) instance to query (default: %s)' %
-                          (site_params.EXTERNAL_GOB_INSTANCE))
+                     help=('Gerrit (on borg) instance to query '
+                           '(default: %(default)s)'))
 
   group = parser.add_argument_group('CL options')
   _AddCommonOptions(parser, group)
diff --git a/scripts/gs_fetch_binpkg.py b/scripts/gs_fetch_binpkg.py
index 8b6fcbb..ed3266f 100644
--- a/scripts/gs_fetch_binpkg.py
+++ b/scripts/gs_fetch_binpkg.py
@@ -37,7 +37,7 @@
   temp_path = '%s.tmp' % filename
   osutils.SafeUnlink(temp_path)
   try:
-    ctx.Copy(uri, temp_path, retries=10)
+    ctx.Copy(uri, temp_path)
     shutil.move(temp_path, filename)
   finally:
     osutils.SafeUnlink(temp_path)
diff --git a/scripts/install_toolchain_unittest.py b/scripts/install_toolchain_unittest.py
index 9211dde..03c91c8 100644
--- a/scripts/install_toolchain_unittest.py
+++ b/scripts/install_toolchain_unittest.py
@@ -9,6 +9,7 @@
 from chromite.lib import cros_test_lib
 from chromite.lib import osutils
 from chromite.lib import sysroot_lib
+from chromite.lib import unittest_lib
 from chromite.scripts import install_toolchain
 
 
@@ -35,6 +36,8 @@
                       'CHOST="%s"' % self.chost_value)
 
     self.sysroot_dir = os.path.join(self.tempdir, 'build/board')
+    # make.conf needs to exist to correctly read back config.
+    unittest_lib.create_stub_make_conf(self.sysroot_dir)
 
   def testInvalidArgs(self):
     """Test invalid argument parsing."""
diff --git a/scripts/lts_kernel_uprev b/scripts/lts_kernel_uprev
new file mode 120000
index 0000000..b68b744
--- /dev/null
+++ b/scripts/lts_kernel_uprev
@@ -0,0 +1 @@
+wrapper3.py
\ No newline at end of file
diff --git a/scripts/lts_kernel_uprev.py b/scripts/lts_kernel_uprev.py
new file mode 100644
index 0000000..2842c34
--- /dev/null
+++ b/scripts/lts_kernel_uprev.py
@@ -0,0 +1,358 @@
+# Copyright 2021 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Uprev Chrome OS LTS kernel.
+
+Update Chrome OS manifest commit ids to the latest LTS commit ids used in
+kernel repo.
+
+Assumptions:
+  1. The user has a full chromiumos checkout.
+  2. XML structure follows //project/{name|path|revision}.
+  3. Kernel repos have name="chromiumos/third_party/kernel".
+  4. Each kernel repo revision is unique.
+"""
+
+import datetime
+import logging
+import os
+from pathlib import Path
+import re
+from typing import Dict, List, Optional
+import xml.etree.ElementTree as ET
+
+from chromite.lib import commandline
+from chromite.lib import constants
+from chromite.lib import cros_build_lib
+from chromite.lib import git
+from chromite.lib import osutils
+from chromite.lib import uri_lib
+
+
+def _parse_iso_date_str(date_str: str) -> datetime.datetime:
+  """Transform ISO date string into a datetime.
+
+  Args:
+    date_str: ISO date string.
+
+  Returns:
+    A datetime object representing the same time as date_str.
+  """
+  try:
+    return datetime.datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S %z')
+  except TypeError:
+    return None
+
+
+class LtsKernelUprev():
+  """Class to represent upreving LTS kernels."""
+
+  KERNEL_PROJECT_NAME = 'chromiumos/third_party/kernel'
+
+  def __init__(self, release_milestone: str, buildroot: Path):
+    """Initialize the LtsKernelUprev class.
+
+    Args:
+      release_milestone: Milestone to use for LTS kernel uprev.
+      buildroot: Path to chromiumos checkout.
+    """
+    self.release_milestone = release_milestone
+    self.buildroot = buildroot
+    self.kernel_repo_path = buildroot / 'src/third_party/kernel'
+    self.manifest_repo_path = buildroot / 'manifest-internal'
+    self.full_manifest_path = self.manifest_repo_path / 'full.xml'
+
+  def get_branch_name(self) -> str:
+    """Determine branch stem using the kernel repo path and release milestone.
+
+    Returns:
+      The stem of branches in the kernel repo which contain the release
+      milestone, or '' if no milestone branches are found.
+    """
+    kernel_upstream_path = self.kernel_repo_path / 'upstream'
+    release_branches = cros_build_lib.run(
+        [
+            'git',
+            'for-each-ref',
+            '--format',
+            '%(refname:lstrip=-1)',
+            f'refs/remotes/cros/release-{self.release_milestone}-*',
+        ],
+        capture_output=True,
+        encoding='utf-8',
+        cwd=kernel_upstream_path).stdout.splitlines()
+    return self._get_branch_stem(release_branches)
+
+  def _get_branch_stem(self, branches: List[str]) -> str:
+    """Determine branch stem given a list of branches.
+
+    Args:
+      branches: All branches containing the release milestone (e.g. ['remotes/
+        cros/release-R96-14268.B-chromeos-4.4', 'remotes/cros/release-R96-14268.
+        B-chromeos-5.10']).
+
+    Returns:
+      The stem of branches in the kernel repo which contain the release
+      milestone (e.g. 'release-R96-14268.B-chromeos-').
+    """
+    # Select any branch because they all share the same prefix.
+    try:
+      branch = branches[0].strip()
+    except IndexError:
+      return None
+    # Remove remote prefix.
+    branch = os.path.basename(branch)
+    # Find and remove the kernel version.
+    branch_kernel_version = branch.split('-')[-1]
+    branch_stem = branch.replace(branch_kernel_version, '')
+    return branch_stem
+
+  def find_new_kernel_commit_ids(
+      self, branch_stem: str, manifest_tree: ET.ElementTree) -> Dict[str, str]:
+    """Determine latest commit id for each kernel repo.
+
+    Args:
+      branch_stem: The stem of branches for the release milestone.
+      manifest_tree: Representation of manifest XML hierarchy.
+
+    Returns:
+      Mapping of strings to find -> replace in XML manifest.
+    """
+    replace_mapping = {}
+    for kernel_element in manifest_tree.getroot().findall('.//project'):
+      if kernel_element.attrib['name'] == self.KERNEL_PROJECT_NAME:
+        kernel_path = self.buildroot / kernel_element.attrib['path']
+        orig_kernel_version = os.path.basename(kernel_path)
+        # Check if this is a test branch (e.g. v5.10-arcvm).
+        if re.match(r'^v[0-9\.]+-[a-zA-Z]+$', orig_kernel_version):
+          logging.info('Leaving test branch unchanged: %s', orig_kernel_version)
+          replace_mapping[orig_kernel_version] = {
+              'original_revision': kernel_element.attrib['revision'],
+              'new_revision': kernel_element.attrib['revision'],
+              'original_date_str': None,
+              'new_date_str': None,
+          }
+          continue
+        # Remove first 'v' from repo kernel version (e.g. v5.10) to get
+        # branch-style kernel version (e.g. 5.10).
+        kernel_version = orig_kernel_version.replace('v', '', 1)
+        branch_name = f'{branch_stem}{kernel_version}'
+        if not os.path.exists(kernel_path):
+          logging.warning('Could not find "%s". Skipping.', kernel_path)
+          continue
+
+        try:
+          branch_tag = cros_build_lib.run(
+              ['git', 'describe', f'remotes/cros/{branch_name}'],
+              capture_output=True,
+              encoding='utf-8',
+              cwd=kernel_path).stdout.strip()
+        except cros_build_lib.RunCommandError as e:
+          logging.warning(
+              'No tag in "%s" for branch "remotes/cros/%s: %s". Skipping.',
+              kernel_path, branch_name, e)
+          continue
+
+        if not branch_tag:
+          logging.warning('No branch found for "%s": "%s"', kernel_path,
+                          branch_name)
+          continue
+
+        branch_commit_id = git.GetGitRepoRevision(
+            kernel_path, branch=branch_tag)
+        orig_rev = kernel_element.attrib['revision']
+        kernel_element.attrib['revision'] = branch_commit_id
+        if orig_rev != branch_commit_id:
+          orig_date_str = self.get_commit_date(kernel_path, orig_rev)
+          new_date_str = self.get_commit_date(kernel_path, branch_commit_id)
+          replace_mapping[orig_kernel_version] = {
+              'original_revision': orig_rev,
+              'new_revision': branch_commit_id,
+              'original_date_str': orig_date_str,
+              'new_date_str': new_date_str,
+          }
+          logging.info('Version %s: replace "%s" with "%s"', kernel_version,
+                       orig_rev, branch_commit_id)
+    return replace_mapping
+
+  def get_commit_date(self, kernel_repo: str, commit_id: str) -> str:
+    """Determine date of a given commit.
+
+    Args:
+      kernel_repo: Path to repo containing commit id.
+      commit_id: Unique id representing a commit in kernel_repo.
+
+    Returns:
+      Date of commit.
+    """
+    if not git.IsSHA1(commit_id):
+      logging.warning(
+          'Error checking date of "%s": not a valid SHA1, skipping.', commit_id)
+      return None
+    cmd = [
+        'git',
+        'show',
+        '--no-patch',
+        '--no-notes',
+        '--pretty=%cd',
+        '--date=iso',
+        commit_id,
+    ]
+    return cros_build_lib.run(
+        cmd, capture_output=True, encoding='utf-8',
+        cwd=kernel_repo).stdout.strip('\n')
+
+  def remove_invalid_revisions(self, replace_mapping: Dict[str, str]):
+    """Remove commit id revisions that are invalid by modifying dict.
+
+    Revisions are invalid if the replacement commit id occurred before the
+    original commit id.
+
+    Args:
+      replace_mapping: Mapping from original to new commit id.
+    """
+    invalid_revisions = []
+    for kernel_version, revisions in replace_mapping.items():
+      orig_date_str = revisions['original_date_str']
+      new_date_str = revisions['new_date_str']
+      orig_date = _parse_iso_date_str(orig_date_str)
+      new_date = _parse_iso_date_str(new_date_str)
+      if orig_date and new_date and orig_date > new_date:
+        kernel_path = self.kernel_repo_path / kernel_version
+        logging.warning(
+            'Skipping "%s": commit id "%s" (%s) more recent than new commit id '
+            '"%s" (%s)', kernel_path, revisions['original_revision'],
+            orig_date_str, revisions['new_revision'], new_date_str)
+        invalid_revisions.append(kernel_version)
+    for rev in invalid_revisions:
+      del replace_mapping[rev]
+
+  def pretty_update_xml(self, replace_mapping: Dict[str, str],
+                        full_manifest_path: str):
+    """Use replace_mapping to update manifest XML retaining formatting.
+
+    Args:
+      replace_mapping: Mapping of strings to find -> replace in XML manifest.
+      full_manifest_path: Path to XML manifest.
+    """
+    manifest_str = osutils.ReadFile(full_manifest_path)
+    for revisions in replace_mapping.values():
+      orig_str = f'revision="{revisions["original_revision"]}"'
+      new_str = f'revision="{revisions["new_revision"]}"'
+      manifest_str = manifest_str.replace(orig_str, new_str)
+    osutils.WriteFile(full_manifest_path, manifest_str)
+
+  def create_cl(self, commit_message: str) -> str:
+    """Create and upload a CL in the manifest repo.
+
+    Args:
+      commit_message: CL commit message.
+
+    Returns:
+      URI of uploaded CL.
+    """
+    try:
+      git.AddPath(self.full_manifest_path)
+      git.Commit(self.manifest_repo_path, commit_message)
+      git_stdout = git.UploadCL(
+          self.manifest_repo_path, 'cros-internal', 'main',
+          capture_output=True).stdout
+      return uri_lib.ShortenUri(git.GetUrlFromRemoteOutput(git_stdout))
+    except cros_build_lib.RunCommandError as e:
+      cros_build_lib.Die(f'Error creating CL: {e}')
+
+
+def get_parser() -> commandline.ArgumentParser:
+  """Creates the argparse parser.
+
+  Returns:
+    Argument parser.
+  """
+  parser = commandline.ArgumentParser(description=__doc__)
+  parser.add_argument(
+      '--release', required=True, help='Release milestone, e.g. R96')
+  parser.add_argument(
+      '--buildroot',
+      default=constants.SOURCE_ROOT,
+      type='path',
+      help='Path to chromiumos checkout')
+  return parser
+
+
+def parse_args(argv: List[str]) -> commandline.ArgumentNamespace:
+  """Parse and validate CLI arguments.
+
+  Args:
+    argv: Arguments passed via CLI.
+
+  Returns:
+    Validated argument namespace.
+  """
+  parser = get_parser()
+  options = parser.parse_args(argv)
+  if not re.match(r'^R[0-9]+$', options.release):
+    cros_build_lib.Die(
+        'Please provide a release milestone of the format R[release number] '
+        'e.g. R96')
+  options.buildroot = Path(options.buildroot)
+  options.Freeze()
+  return options
+
+
+def main(argv: List[str]) -> Optional[int]:
+  options = parse_args(argv)
+  lts = LtsKernelUprev(options.release, options.buildroot)
+
+  # Determine branch stem based on kernel repo and release milestone.
+  logging.info('Using release "%s" and chromiumos checkout at "%s"',
+               lts.release_milestone, lts.buildroot)
+  # Ensure kernel refs are up-to-date.
+  git.RunGit(lts.kernel_repo_path / 'upstream', ['fetch', 'cros'])
+  branch_stem = lts.get_branch_name()
+  if not branch_stem:
+    cros_build_lib.Die(
+        f'Could not determine a branch stem for repo "{lts.kernel_repo_path}" '
+        f'and release "{lts.release_milestone}".')
+  logging.info('Using branch stem "%s"', branch_stem)
+
+  # Ensure manifest repo is up-to-date.
+  git.SyncPushBranch(lts.manifest_repo_path, 'cros-internal',
+                     'refs/remotes/cros-internal/main')
+  git.RunGit(lts.manifest_repo_path, ['fetch', 'cros-internal'])
+
+  # Read manifest XML.
+  try:
+    manifest_tree = ET.parse(lts.full_manifest_path)
+  except ET.ParseError as e:
+    cros_build_lib.Die(f'Error parsing XML: {e}')
+
+  # Find new commit ids for each kernel repo, ensuring they are newer than the
+  # existing commit ids.
+  replace_mapping = lts.find_new_kernel_commit_ids(branch_stem, manifest_tree)
+  lts.remove_invalid_revisions(replace_mapping)
+
+  # Using built-in XML functionality causes formatting changes.
+  # Use string.replace to preserve formatting.
+  lts.pretty_update_xml(replace_mapping, lts.full_manifest_path)
+
+  # If available, add date details for manifest commit id changes to give
+  # context in the CL.
+  commit_details = ''
+  for kernel_version, revs in replace_mapping.items():
+    if revs['original_date_str'] and revs['new_date_str']:
+      commit_details += (
+          f'\nKernel {kernel_version}: Replaced commit id from '
+          f'"{revs["original_date"]}" with commit id from "revs["new_date"]"')
+  commit_message = f"""LTS: update kernel commit ids for LTS branches
+
+This CL was created automatically. For more details see go/
+chromeos-lts-kernel-uprev.
+{commit_details}
+
+BUG=None
+TEST=CQ"""
+
+  uploaded_cl_uri = lts.create_cl(commit_message)
+  if uploaded_cl_uri:
+    logging.info('Successfully uploaded CL: %s', uploaded_cl_uri)
diff --git a/scripts/lts_kernel_uprev_unittest.py b/scripts/lts_kernel_uprev_unittest.py
new file mode 100644
index 0000000..b5bcc2c
--- /dev/null
+++ b/scripts/lts_kernel_uprev_unittest.py
@@ -0,0 +1,204 @@
+# Copyright 2021 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Unit tests for LTS_kernel_uprev."""
+
+import copy
+import os
+from unittest.mock import patch
+import xml.etree.ElementTree as ET
+
+from chromite.lib import cros_build_lib
+from chromite.lib import cros_test_lib
+from chromite.lib import git
+from chromite.lib import osutils
+from chromite.scripts import lts_kernel_uprev
+
+SAMPLE_MANIFEST_XML = """<?xml version="1.0" encoding="UTF-8"?>
+<manifest>
+  <include name="_remotes.xml" />
+  <default revision="refs/heads/main"
+           remote="cros"
+           sync-j="8" />
+
+  <include name="_kernel_upstream.xml" />
+
+  <project path="src/third_party/kernel/v5.10"
+           name="chromiumos/third_party/kernel"
+           revision="refs/heads/chromeos-5.10" />
+  <project path="src/third_party/kernel/v5.10-arcvm"
+           name="chromiumos/third_party/kernel"
+           revision="refs/heads/chromeos-5.10-arcvm" />
+ </manifest>"""
+
+SAMPLE_CL_UPLOAD = """remote: Processing changes: refs: 1, new: 1, done
+remote:
+remote: SUCCESS
+remote:
+remote:   https://chrome-internal-review.googlesource.com/c/chromeos/\
+manifest-internal/+/4286699 LTS: update kernel commit ids for LTS branches [NEW]
+remote:
+To https://chrome-internal-review.googlesource.com/chromeos/manifest-internal
+ * [new reference]         main -> refs/for/main
+"""
+
+
+# Helper functions to mock calls within lts_kernel_uprev methods
+def branches_mock(run_cmd, **unused_kwargs):
+  if 'refs/remotes/cros/release-R96-*' in run_cmd:
+    return cros_build_lib.CommandResult(
+        stdout=('release-R96-14268.B-chromeos-5.10\nrelease-R96-14268.'
+                'B-chromeos-5.10-arcvm\nrelease-R96-14268.B-chromeos-5.'
+                '4\nrelease-R96-14268.B-chromeos-5.4-arcvm\nrelease-R96-14268.'
+                'B-chromeos-5.4-manatee'))
+  else:
+    return cros_build_lib.CommandResult(stdout=(''))
+
+
+def tag_mock(*unused_args, **unused_kwargs):
+  return cros_build_lib.CommandResult(stdout='v5.10.71-12106-gbca20254cbdc')
+
+
+def git_rev_mock(*unused_args, **unused_kwargs):
+  return 'e028e1181cdcfc94865861d460c96ddb5e08bb6f'
+
+
+def commit_date_mock(unused_obj, unused_repo, commit_id):
+  if commit_id == 'e028e1181cdcfc94865861d460c96ddb5e08bb6f':
+    return '2021-10-28 21:52:39 +0000'
+  else:
+    return None
+
+
+def git_commit_mock(*unused_args, **unused_kwargs):
+  return cros_build_lib.CommandResult(stdout='2021-05-01 03:51:23 +0000')
+
+
+class CrosLtsKernelUprevTests(cros_test_lib.TempDirTestCase):
+  """Tests for LTS kernel uprev functionality."""
+
+  def setUp(self):
+    """General set up for LTS kernel uprev tests."""
+    options = lts_kernel_uprev.parse_args(['--release=R96'])
+    self.LtsKernelUprev = lts_kernel_uprev.LtsKernelUprev(
+        options.release, options.buildroot)
+    self.buildroot = options.buildroot
+    # Write a sample manifest.
+    self.temp_manifest_path = os.path.join(self.tempdir, 'ltsTestManifest.xml')
+    osutils.WriteFile(self.temp_manifest_path, SAMPLE_MANIFEST_XML)
+
+  @patch.object(cros_build_lib, 'run', new_callable=lambda: branches_mock)
+  def test_get_branch_name(self, unused_patch_run):
+    """Tests LtsKernelUprev.get_branch_name returns expected results."""
+    # Test a valid milestone.
+    branch_name = self.LtsKernelUprev.get_branch_name()
+    self.assertEqual('release-R96-14268.B-chromeos-', branch_name)
+    # Test a non-existent milestone.
+    lts_no_milestone = lts_kernel_uprev.LtsKernelUprev('NoMilestone',
+                                                       self.buildroot)
+    no_branch = lts_no_milestone.get_branch_name()
+    self.assertIsNone(no_branch)
+
+  @patch.object(cros_build_lib, 'run', new_callable=lambda: tag_mock)
+  @patch.object(git, 'GetGitRepoRevision', new_callable=lambda: git_rev_mock)
+  @patch.object(
+      lts_kernel_uprev.LtsKernelUprev,
+      'get_commit_date',
+      new_callable=lambda: commit_date_mock)
+  def test_find_new_kernel_commit_ids(self, unused_patch_run,
+                                      unused_patch_gitrev,
+                                      unused_patch_commitdate):
+    """Tests LtsKernelUprev.find_new_kernel_commit_ids returns exp. results."""
+    branch_name = 'release-R96-14268.B-chromeos-'
+    xml_tree = ET.parse(self.temp_manifest_path)
+    # Test with a valid manifest.
+    replace_mapping = self.LtsKernelUprev.find_new_kernel_commit_ids(
+        branch_name, xml_tree)
+    self.assertEqual(
+        {
+            'v5.10': {
+                'new_revision': 'e028e1181cdcfc94865861d460c96ddb5e08bb6f',
+                'original_revision': 'refs/heads/chromeos-5.10',
+                'original_date_str': None,
+                'new_date_str': '2021-10-28 21:52:39 +0000',
+            },
+            'v5.10-arcvm': {
+                'new_revision': 'refs/heads/chromeos-5.10-arcvm',
+                'original_revision': 'refs/heads/chromeos-5.10-arcvm',
+                'original_date_str': None,
+                'new_date_str': None,
+            },
+        }, replace_mapping)
+    # Test with an invalid kernel repo path in the manifest.
+    xml_invalid_kernel = os.path.join(self.tempdir,
+                                      'ltsTestInvalidKernelManifest.xml')
+    osutils.WriteFile(
+        xml_invalid_kernel,
+        SAMPLE_MANIFEST_XML.replace('kernel/v5.10', 'kernel/invalid'))
+    xml_tree = ET.parse(xml_invalid_kernel)
+    branch_name = 'release-R96-14268.B-chromeos-'
+    replace_mapping = self.LtsKernelUprev.find_new_kernel_commit_ids(
+        branch_name, xml_tree)
+    self.assertEqual({}, replace_mapping)
+
+  @patch.object(cros_build_lib, 'run', new_callable=lambda: git_commit_mock)
+  def test_get_commit_date(self, unused_patch_run):
+    """Tests LtsKernelUprev.get_commit_date returns expected results."""
+    kernel_repo_path = self.buildroot / 'src/third_party/kernel/v5.10'
+    # Test with a valid commit id.
+    commit_id_date_str = self.LtsKernelUprev.get_commit_date(
+        kernel_repo_path, '355a95829e9f0f868603b87cc881e0355a26ec16')
+    self.assertEqual('2021-05-01 03:51:23 +0000', commit_id_date_str)
+    # Test with an invalid commit id.
+    commit_id_date_str = self.LtsKernelUprev.get_commit_date(
+        kernel_repo_path, '3049ae9b253')
+    self.assertIsNone(commit_id_date_str)
+
+  def test_remove_invalid_revisions(self):
+    """Tests LtsKernelUprev.remove_invalid_revisions has exp. side effect."""
+    # Test valid commit id revisions are not removed.
+    replace_mapping = {
+        'v5.10': {
+            'original_revision': '355a95829e9f0f868603b87cc881e0355a26ec16',
+            'new_revision': 'ff5140f08b2a362171848f9215504e801863ab86',
+            'original_date_str': '2021-05-01 03:51:23 +0000',
+            'new_date_str': '2021-05-01 09:11:33 +0000',
+        },
+        'v5.4': {
+            'original_revision': '355a95829e9f0f868603b87cc881e0355a26ec16',
+            'new_revision': 'refs/heads/chromeos-5.10',
+            'original_date_str': '2021-05-01 03:51:23 +0000',
+            'new_date_str': None,
+        },
+    }
+    replace_mapping_copy = copy.deepcopy(replace_mapping)
+    self.LtsKernelUprev.remove_invalid_revisions(replace_mapping)
+    self.assertEqual(replace_mapping_copy, replace_mapping)
+    # Test invalid commit id revisions are removed.
+    replace_mapping = {
+        'v5.10': {
+            'new_revision': '355a95829e9f0f868603b87cc881e0355a26ec16',
+            'original_revision': 'ff5140f08b2a362171848f9215504e801863ab86',
+            'new_date_str': '2021-05-01 03:51:23 +0000',
+            'original_date_str': '2021-05-01 09:11:33 +0000',
+        },
+    }
+    self.LtsKernelUprev.remove_invalid_revisions(replace_mapping)
+    self.assertEqual({}, replace_mapping)
+
+  def test_pretty_update_xml(self):
+    """Tests LtsKernelUprev.pretty_update_xml has expected side effect."""
+    replace_mapping = {
+        'v5.10': {
+            'new_revision': 'e028e1181cdcfc94865861d460c96ddb5e08bb6f',
+            'original_revision': 'refs/heads/chromeos-5.10',
+        },
+    }
+    self.LtsKernelUprev.pretty_update_xml(replace_mapping,
+                                          self.temp_manifest_path)
+    updated_manifest_xml = osutils.ReadFile(self.temp_manifest_path)
+    expected_manifest_xml = SAMPLE_MANIFEST_XML.replace(
+        'revision="refs/heads/chromeos-5.10"',
+        'revision="e028e1181cdcfc94865861d460c96ddb5e08bb6f"')
+    self.assertEqual(updated_manifest_xml, expected_manifest_xml)
diff --git a/scripts/pushimage.py b/scripts/pushimage.py
index bd16e5c..4d224a5 100644
--- a/scripts/pushimage.py
+++ b/scripts/pushimage.py
@@ -46,6 +46,7 @@
     constants.IMAGE_TYPE_FACTORY,
     constants.IMAGE_TYPE_FIRMWARE,
     constants.IMAGE_TYPE_ACCESSORY_USBPD,
+    constants.IMAGE_TYPE_HPS_FIRMWARE,
     constants.IMAGE_TYPE_ACCESSORY_RWSIG,
     constants.IMAGE_TYPE_BASE,
     constants.IMAGE_TYPE_GSC_FIRMWARE,
@@ -400,6 +401,7 @@
     recovery_basename = _ImageNameBase(constants.IMAGE_TYPE_RECOVERY)
     factory_basename = _ImageNameBase(constants.IMAGE_TYPE_FACTORY)
     firmware_basename = _ImageNameBase(constants.IMAGE_TYPE_FIRMWARE)
+    hps_firmware_basename = _ImageNameBase(constants.IMAGE_TYPE_HPS_FIRMWARE)
     acc_usbpd_basename = _ImageNameBase(constants.IMAGE_TYPE_ACCESSORY_USBPD)
     acc_rwsig_basename = _ImageNameBase(constants.IMAGE_TYPE_ACCESSORY_RWSIG)
     gsc_firmware_basename = _ImageNameBase(constants.IMAGE_TYPE_GSC_FIRMWARE)
@@ -417,6 +419,7 @@
         (hwqual_tarball, None, None),
         ('stateful.tgz', None, None),
         ('dlc', None, None),
+        (constants.ARTIFACT_PROVENANCE_MANIFESTS, None, None),
         (constants.QUICK_PROVISION_PAYLOAD_KERNEL, None, None),
         (constants.QUICK_PROVISION_PAYLOAD_ROOTFS, None, None),
         (constants.QUICK_PROVISION_PAYLOAD_MINIOS, None, None),
@@ -436,6 +439,9 @@
         ('firmware_from_source.tar.bz2', firmware_basename, 'tar.bz2',
          constants.IMAGE_TYPE_FIRMWARE),
 
+        ('firmware_from_source.tar.bz2', hps_firmware_basename, 'tar.bz2',
+         constants.IMAGE_TYPE_HPS_FIRMWARE),
+
         ('firmware_from_source.tar.bz2', acc_usbpd_basename, 'tar.bz2',
          constants.IMAGE_TYPE_ACCESSORY_USBPD),
 
@@ -496,6 +502,12 @@
           _AddToFilesToSign(image_type, dst, suffix)
 
     logging.debug('Files to sign: %s', files_to_sign)
+    unused_sign_types = set(sign_types or []) - set(
+        x for x, _, _ in files_to_sign)
+    if unused_sign_types:
+      logging.warning('Some sign types were unused: %s',
+                      ' '.join(unused_sign_types))
+
     # Now go through the subset for signing.
     for image_type, dst_name, suffix in files_to_sign:
       try:
diff --git a/scripts/pushimage_unittest.py b/scripts/pushimage_unittest.py
index cfa7d89..9f49256 100644
--- a/scripts/pushimage_unittest.py
+++ b/scripts/pushimage_unittest.py
@@ -290,7 +290,7 @@
     with mock.patch.object(gs.GSContext, 'Exists', return_value=True):
       urls = pushimage.PushImage('/src', 'test.board', 'R34-5126.0.0',
                                  sign_types=['recovery'])
-    self.assertEqual(self.gs_mock.call_count, 32)
+    self.assertEqual(self.gs_mock.call_count, 36)
     self.assertTrue(self.mark_mock.called)
     self.assertEqual(urls, EXPECTED)
 
@@ -308,7 +308,7 @@
     with mock.patch.object(gs.GSContext, 'Exists', return_value=True):
       urls = pushimage.PushImage('/src', 'test.board', 'R34-5126.0.0',
                                  sign_types=['base'])
-    self.assertEqual(self.gs_mock.call_count, 34)
+    self.assertEqual(self.gs_mock.call_count, 38)
     self.assertTrue(self.mark_mock.called)
     self.assertEqual(urls, EXPECTED)
 
@@ -326,7 +326,7 @@
     with mock.patch.object(gs.GSContext, 'Exists', return_value=True):
       urls = pushimage.PushImage('/src', 'board2', 'R34-5126.0.0',
                                  sign_types=['gsc_firmware'])
-    self.assertEqual(self.gs_mock.call_count, 32)
+    self.assertEqual(self.gs_mock.call_count, 36)
     self.assertTrue(self.mark_mock.called)
     self.assertEqual(urls, EXPECTED)
 
@@ -334,7 +334,7 @@
     """Verify nothing is signed when we request an unavailable type"""
     urls = pushimage.PushImage('/src', 'test.board', 'R34-5126.0.0',
                                sign_types=['nononononono'])
-    self.assertEqual(self.gs_mock.call_count, 30)
+    self.assertEqual(self.gs_mock.call_count, 34)
     self.assertFalse(self.mark_mock.called)
     self.assertEqual(urls, {})
 
diff --git a/scripts/repo_sync_manifest.py b/scripts/repo_sync_manifest.py
index 2099bbb..0f92b73 100644
--- a/scripts/repo_sync_manifest.py
+++ b/scripts/repo_sync_manifest.py
@@ -204,9 +204,6 @@
   if options.copy_repo:
     repo.PreLoad(options.copy_repo)
 
-  if repository.IsARepoRoot(options.repo_root):
-    repo.BuildRootGitCleanup(prune_all=True)
-
   repo.Sync(local_manifest=local_manifest, detach=True)
 
   if options.gerrit_patches:
diff --git a/scripts/strip_package b/scripts/strip_package
new file mode 120000
index 0000000..b68b744
--- /dev/null
+++ b/scripts/strip_package
@@ -0,0 +1 @@
+wrapper3.py
\ No newline at end of file
diff --git a/scripts/strip_package.py b/scripts/strip_package.py
new file mode 100644
index 0000000..a49bb90
--- /dev/null
+++ b/scripts/strip_package.py
@@ -0,0 +1,76 @@
+# Copyright 2021 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Strip packages and place them in <sysroot>/stripped-packages."""
+
+import os
+import sys
+from typing import List
+
+from chromite.lib import build_target_lib
+from chromite.lib import commandline
+from chromite.lib import constants
+from chromite.lib import cros_build_lib
+from chromite.lib import osutils
+
+# The builder module lives in the devserver path.
+sys.path.append('/usr/lib/devserver/')
+import builder
+
+_DEFAULT_MASK = 'DEFAULT_INSTALL_MASK'
+
+def create_parser() -> commandline.ArgumentParser:
+  """Creates the cmdline argparser, populates the options and description."""
+  parser = commandline.ArgumentParser(description=__doc__)
+
+  group = parser.add_mutually_exclusive_group(required=True)
+  group.add_argument('--board',
+                     default=cros_build_lib.GetDefaultBoard(),
+                     help='The board that processed packages belong to.')
+  group.add_argument('--sysroot',
+                     type='path',
+                     help='Sysroot that processed packages belong to. '
+                     'This is incompatible with --board.')
+
+  parser.add_argument('--deep',
+                      action='store_true',
+                      default=False,
+                      help='Also strip dependencies of packages.')
+  parser.add_argument('packages',
+                      nargs='+',
+                      metavar='package',
+                      help='Packages to strip.')
+  return parser
+
+
+def populate_install_mask() -> bool:
+  """Extract the default install mask and populate the local environment."""
+  env_var_value = osutils.SourceEnvironment(
+      os.path.join(constants.CROSUTILS_DIR, 'common.sh'),
+      [_DEFAULT_MASK],
+      multiline=True)
+
+  if _DEFAULT_MASK not in env_var_value:
+    return False
+  os.environ[_DEFAULT_MASK] = env_var_value[_DEFAULT_MASK]
+  return True
+
+
+def main(argv: List[str]) -> int:
+  """Main function."""
+  cros_build_lib.AssertInsideChroot()
+  parser = create_parser()
+  options = parser.parse_args(argv)
+  options.Freeze()
+
+  if options.sysroot is not None:
+    sysroot = options.sysroot
+  else:
+    sysroot = build_target_lib.get_default_sysroot_path(options.board)
+
+  if not populate_install_mask():
+    return False
+  if not builder.UpdateGmergeBinhost(sysroot, options.packages, options.deep):
+    return 1
+  return 0
diff --git a/scripts/upload_symbols.py b/scripts/upload_symbols.py
index 2d94fc6..b374b01 100644
--- a/scripts/upload_symbols.py
+++ b/scripts/upload_symbols.py
@@ -33,6 +33,7 @@
 from chromite.lib import path_util
 from chromite.lib import retry_stats
 from chromite.scripts import cros_generate_breakpad_symbols
+from chromite.utils import timer
 
 
 # Needs to be after chromite imports.
@@ -441,7 +442,7 @@
             return True
           return False
 
-        with cros_build_lib.TimedSection() as timer:
+        with timer.Timer() as t:
           retry_stats.RetryWithStats(
               UPLOAD_STATS, ShouldRetryUpload, MAX_RETRIES,
               UploadSymbolFile,
@@ -450,7 +451,7 @@
               log_all_retries=True)
         if s.status != SymbolFile.DUPLICATE:
           logging.info('upload of %s with size %10i bytes took %s',
-                       s.display_name, s.FileSize(), timer.delta)
+                       s.display_name, s.FileSize(), t)
           s.status = SymbolFile.UPLOADED
       except requests.exceptions.RequestException as e:
         logging.warning('could not upload: %s: HTTP error: %s',
diff --git a/scripts/xz_auto.py b/scripts/xz_auto.py
index 4d6902e..f6b302f 100644
--- a/scripts/xz_auto.py
+++ b/scripts/xz_auto.py
@@ -8,6 +8,8 @@
 
 import getopt
 import os
+import subprocess
+import sys
 
 from chromite.lib import commandline
 from chromite.lib import osutils
@@ -15,30 +17,28 @@
 
 
 PIXZ_DISABLE_VAR = 'FOR_TEST_XZ_AUTO_NO_PIXZ'
+XZ_DISABLE_VAR = 'FOR_TEST_XZ_AUTO_NO_XZ_DECOMPRESSION'
 
 
 @memoize.Memoize
 def HasPixz():
   """Returns path to pixz if it's on PATH or None otherwise."""
-  return osutils.Which('pixz') and not os.environ.get(PIXZ_DISABLE_VAR)
+  return PIXZ_DISABLE_VAR not in os.environ and osutils.Which('pixz')
 
 
-def BasePixzCommand(jobs):
-  """Returns a command that invokes pixz with the given job count."""
-  return ['pixz', '-p', str(jobs)]
+def ParsePixzArgs(argv):
+  """Determines flags to pass to pixz, per argv.
 
-
-def BaseXzCommand(jobs):
-  """Returns a command that invokes xz with the given job count."""
-  return ['xz', f'-T{jobs}']
-
-
-def DetermineFilesPassedToPixz(argv):
-  """Attempt to figure out what file we're trying to compress."""
+  Returns:
+    A tuple containing:
+    - A raw list of flags to pass to pixz.
+    - An optional input file.
+    - An optional output file (only exists if the input file is present).
+  """
   # Glancing at docs, the following opts are supported. -i and -o are ignored,
   # since we assert in `main` that they're not present, but include parsing for
   # them anyway.
-  _, args = getopt.gnu_getopt(
+  flags, args = getopt.gnu_getopt(
       args=argv,
       shortopts='dlxi:o:0123456789p:tkch',
   )
@@ -52,61 +52,127 @@
     file_to_compress = args[0]
     target = args[1]
 
-  return file_to_compress, target
+  raw_flag_list = []
+  for key, val in flags:
+    raw_flag_list.append(key)
+    if val:
+      raw_flag_list.append(val)
+
+  return raw_flag_list, file_to_compress, target
 
 
-def GetCompressCommand(stdout, jobs, argv):
-  """Returns compression command."""
+def Execvp(argv):
+  """Execs the given argv."""
+  os.execvp(argv[0], argv)
+
+
+def ExecCompressCommand(stdout, argv):
+  """Execs compression command."""
   # It appears that in order for pixz to do parallel decompression, compression
   # needs to be done with pixz. xz itself is only capable of parallel
   # compression.
-  if HasPixz():
-    cmd = BasePixzCommand(jobs)
+  if not HasPixz():
+    cmd = ['xz']
 
-    compressed_file_name, specifies_output_file = DetermineFilesPassedToPixz(
-        argv)
-
-    if compressed_file_name:
-      if not (stdout or specifies_output_file):
-        # Pixz defaults to a `.pxz` suffix (or `.tpxz` if it's compressing a
-        # tar file). We need the suffix to be consistent, so force it here.
-        cmd += ['-o', f'{compressed_file_name}.xz']
-    else:
-      cmd += ['-i', '/dev/stdin']
-    return cmd
-
-  cmd = BaseXzCommand(jobs)
-
-  if stdout:
-    cmd.append('-zc')
-  else:
-    cmd.append('-z')
-  return cmd
-
-
-def GetDecompressCommand(stdout, jobs, argv):
-  """Returns decompression command."""
-  if HasPixz():
-    cmd = BasePixzCommand(jobs)
-    cmd.append('-d')
-
-    compressed_file_name, _ = DetermineFilesPassedToPixz(argv)
     if stdout:
-      # Explicitly tell pixz the file is the input, so it will dump the output
-      # to stdout, instead of automatically choosing an output name.
-      cmd.append('-i')
-      if not compressed_file_name:
-        cmd.append('/dev/stdin')
-    elif not compressed_file_name:
-      cmd += ['-i', '/dev/stdin']
-    return cmd
+      cmd.append('-zc')
+    else:
+      cmd.append('-z')
+    cmd += argv
+    Execvp(cmd)
 
-  cmd = BaseXzCommand(jobs)
+  cmd = ['pixz']
+  raw_flag_list, compressed_file_name, output_file = ParsePixzArgs(argv)
+
+  # Pixz treats tarballs specially: if it detects that a tarball has been
+  # passed to it, it'll also write a small index in the output file that
+  # makes operations like listing the tar faster. If this tar autodetection
+  # is enabled and pixz is asked to compress an empty file, it breaks. In
+  # addition, these indices have no apparent impact on decompression
+  # parallelism, so they're not super useful to us. Disable the feature
+  # wholesale.
+  if '-t' not in raw_flag_list:
+    raw_flag_list.append('-t')
+
+  autodelete_input_file = False
+  if not compressed_file_name:
+    assert not output_file
+    compressed_file_name = '/dev/stdin'
+    output_file = '/dev/stdout'
+  elif stdout:
+    output_file = '/dev/stdout'
+  elif not output_file:
+    # Pixz defaults to a `.pxz` suffix (or `.tpxz` if it's compressing a
+    # tar file). We need the suffix to be consistent, so force it here.
+    output_file = f'{compressed_file_name}.xz'
+    autodelete_input_file = True
+
+  cmd += raw_flag_list
+  cmd.append(compressed_file_name)
+  if output_file:
+    cmd.append(output_file)
+
+  if not autodelete_input_file:
+    Execvp(cmd)
+
+  return_code = subprocess.call(cmd)
+  if not return_code:
+    os.unlink(compressed_file_name)
+  sys.exit(return_code)
+
+
+def ExecXzDecompressCommand(stdout, argv):
+  """Executes `xz` with the given params."""
+  cmd = ['xz']
   if stdout:
     cmd.append('-dc')
   else:
     cmd.append('-d')
-  return cmd
+  cmd += argv
+  Execvp(cmd)
+
+
+def ExecDecompressCommand(stdout, argv):
+  """Execs decompression command."""
+  if not HasPixz():
+    ExecXzDecompressCommand(stdout, argv)
+
+  cmd = ['pixz', '-d']
+  raw_flag_list, compressed_file_name, output_file_name = ParsePixzArgs(argv)
+  cmd += raw_flag_list
+
+  assert compressed_file_name or not output_file_name
+  if not compressed_file_name:
+    Execvp(cmd)
+
+  # HACK: When passed a file, pixz will jump around it and try to find the
+  # file's index. If the file we originally compressed was empty and we
+  # requested no index, pixz will error out because lzma will report no
+  # entries to it, and pixz doesn't handle that well.
+  #
+  # Since we need to support files with indices and without, we can't pass
+  # `-t`. If we do, that causes pixz to error out occasionally on tar files
+  # with indices. :(
+  #
+  # In any case, at the time I checked, empty xz files are 32 bytes, so just
+  # opt to use xz for anything under 4KB. pixz archives are xz-compatible
+  # anyway.
+  if (XZ_DISABLE_VAR not in os.environ and
+      os.path.isfile(compressed_file_name) and
+      os.path.getsize(compressed_file_name) <= 4 * 1024):
+    ExecXzDecompressCommand(stdout, argv)
+
+  cmd.append(compressed_file_name)
+
+  # Explicitly tell pixz the file is the input, so it will dump the output
+  # to stdout, instead of automatically choosing an output name.
+  if stdout:
+    output_file_name = '/dev/stdout'
+
+  if output_file_name:
+    cmd.append(output_file_name)
+
+  Execvp(cmd)
 
 
 def GetParser():
@@ -132,12 +198,7 @@
   if '-i' in argv or '-o' in argv:
     parser.error('It is invalid to use -i or -o with xz_auto')
 
-  # Use half of our CPUs to avoid starving other processes.
-  jobs = max(1, os.cpu_count() // 2)
-
   if known_args.decompress:
-    args = GetDecompressCommand(known_args.stdout, jobs, argv)
+    ExecDecompressCommand(known_args.stdout, argv)
   else:
-    args = GetCompressCommand(known_args.stdout, jobs, argv)
-
-  os.execvp(args[0], args + argv)
+    ExecCompressCommand(known_args.stdout, argv)
diff --git a/scripts/xz_auto_unittest.py b/scripts/xz_auto_unittest.py
index 0669b1b..76cfd62 100644
--- a/scripts/xz_auto_unittest.py
+++ b/scripts/xz_auto_unittest.py
@@ -7,6 +7,7 @@
 import os
 from pathlib import Path
 import unittest
+from unittest import mock
 
 from chromite.lib import cros_build_lib
 from chromite.lib import cros_test_lib
@@ -25,124 +26,177 @@
 class XzAutoTests(cros_test_lib.MockTempDirTestCase):
   """Various tests for xz_auto."""
 
+  TEST_FILE_CONTENTS = (b'', b'some random file contents')
+
   def DisablePixzForCurrentTest(self):
     """Disables the use of pixz for the current test."""
     # This will be cleaned up by cros_test_lib, so no need to addCleanup.
     os.environ[xz_auto.PIXZ_DISABLE_VAR] = '1'
 
-  def testPixzCompressedFileNameDeterminationSeemsToWork(self):
+  def testPixzArgParsingSeemsToWork(self):
     """Tests our detection of file names in pixz commandlines."""
     self.assertEqual(
-        xz_auto.DetermineFilesPassedToPixz(['to_compress.txt']),
-        ('to_compress.txt', None),
+        xz_auto.ParsePixzArgs(['to_compress.txt']),
+        ([], 'to_compress.txt', None),
     )
     self.assertEqual(
-        xz_auto.DetermineFilesPassedToPixz(
-            ['to_compress.txt', 'compressed.txt']),
-        ('to_compress.txt', 'compressed.txt'),
+        xz_auto.ParsePixzArgs(['to_compress.txt', 'compressed.txt']),
+        ([], 'to_compress.txt', 'compressed.txt'),
     )
     self.assertEqual(
-        xz_auto.DetermineFilesPassedToPixz(
-            ['to_compress.txt', '-c', 'compressed.txt', '-9']),
-        ('to_compress.txt', 'compressed.txt'),
+        xz_auto.ParsePixzArgs(['to_compress.txt', '-c', 'compressed.txt',
+                               '-9']),
+        (['-c', '-9'], 'to_compress.txt', 'compressed.txt'),
     )
     self.assertEqual(
-        xz_auto.DetermineFilesPassedToPixz(
+        xz_auto.ParsePixzArgs(
             ['-t', 'to_compress.txt', '-c', 'compressed.txt', '-p', '2']),
-        ('to_compress.txt', 'compressed.txt'),
+        (['-t', '-c', '-p', '2'], 'to_compress.txt', 'compressed.txt'),
     )
     self.assertEqual(
-        xz_auto.DetermineFilesPassedToPixz(
-            ['-tcp2', 'to_compress.txt', 'compressed.txt']),
-        ('to_compress.txt', 'compressed.txt'),
+        xz_auto.ParsePixzArgs(['-tcp2', 'to_compress.txt', 'compressed.txt']),
+        (['-t', '-c', '-p', '2'], 'to_compress.txt', 'compressed.txt'),
     )
 
   @unittest.skipIf(not xz_auto.HasPixz(), 'need pixz for this test')
-  def testPixzCommandCreationSelectsPixzIfAvailable(self):
+  @mock.patch.object(xz_auto, 'Execvp')
+  def testPixzCommandCreationSelectsPixzIfAvailable(self, execvp_mock):
     """Tests that we actually execute pixz when we intend to."""
-    compress_command = xz_auto.GetCompressCommand(
-        stdout=False,
-        jobs=1,
-        argv=['file_to_compress.txt'],
-    )
-    self.assertEqual(compress_command[0], 'pixz')
+    class ExecvpStopError(Exception):
+      """Convenient way to halt execution."""
 
-    decompress_command = xz_auto.GetDecompressCommand(
-        stdout=False,
-        jobs=1,
-        argv=[],
-    )
-    self.assertEqual(decompress_command[0], 'pixz')
+    def execvp_side_effect(argv):
+      """Does testing of our execvp calls."""
+      self.assertEqual(argv[0], 'pixz')
+      raise ExecvpStopError()
 
-  def _TestFileCompressionImpl(self):
+    execvp_mock.side_effect = execvp_side_effect
+    with self.assertRaises(ExecvpStopError):
+      xz_auto.ExecCompressCommand(stdout=False, argv=[])
+
+    with self.assertRaises(ExecvpStopError):
+      xz_auto.ExecDecompressCommand(stdout=False, argv=[])
+
+  def _TestFileCompressionImpl(self, test_empty_file=True):
     """Tests that compressing a file with xz_auto WAI."""
-    file_contents = b'some random file contents'
-    file_location = os.path.join(self.tempdir, 'file.txt')
-    osutils.WriteFile(file_location, file_contents, mode='wb')
-
     xz_auto_script = str(FindXzAutoLocation())
-    cros_build_lib.run(
-        [
-            xz_auto_script,
-            file_location,
-        ],
-        check=True,
-    )
 
-    xz_location = file_location + '.xz'
-    self.assertExists(xz_location)
-    self.assertNotExists(file_location)
-    cros_build_lib.run([
-        xz_auto_script,
-        '--decompress',
-        xz_location,
-    ])
-    self.assertNotExists(xz_location)
-    self.assertExists(file_location)
-    self.assertEqual(
-        osutils.ReadFile(file_location, mode='rb'),
-        file_contents,
-    )
+    test_file_contents = self.TEST_FILE_CONTENTS
+    if not test_empty_file:
+      test_file_contents = (x for x in test_file_contents if x)
+
+    for file_contents in test_file_contents:
+      file_location = os.path.join(self.tempdir, 'file.txt')
+      osutils.WriteFile(file_location, file_contents, mode='wb')
+
+      cros_build_lib.run(
+          [
+              xz_auto_script,
+              file_location,
+          ],
+      )
+
+      xz_location = file_location + '.xz'
+      self.assertExists(xz_location)
+      self.assertNotExists(file_location)
+      cros_build_lib.run([
+          xz_auto_script,
+          '--decompress',
+          xz_location,
+      ])
+      self.assertNotExists(xz_location)
+      self.assertExists(file_location)
+      self.assertEqual(
+          osutils.ReadFile(file_location, mode='rb'),
+          file_contents,
+      )
 
   def _TestStdoutCompressionImpl(self):
     """Tests that compressing stdstreams with xz_auto WAI."""
-    file_contents = b'some random file contents'
     xz_auto_script = str(FindXzAutoLocation())
+    for file_contents in self.TEST_FILE_CONTENTS:
+      run_result = cros_build_lib.run(
+          [
+              xz_auto_script,
+              '-c',
+          ],
+          capture_output=True,
+          input=file_contents,
+      )
 
-    run_result = cros_build_lib.run(
-        [
-            xz_auto_script,
-            '-c',
-        ],
-        capture_output=True,
-        input=file_contents,
-    )
+      compressed_file = run_result.stdout
+      self.assertNotEqual(compressed_file, file_contents)
 
-    compressed_file = run_result.stdout
-    self.assertNotEqual(compressed_file, file_contents)
+      run_result = cros_build_lib.run(
+          [
+              xz_auto_script,
+              '--decompress',
+              '-c',
+          ],
+          input=compressed_file,
+          capture_output=True,
+      )
+      uncompressed_file = run_result.stdout
+      self.assertEqual(file_contents, uncompressed_file)
 
-    run_result = cros_build_lib.run(
-        [
-            xz_auto_script,
-            '--decompress',
-            '-c',
-        ],
-        input=compressed_file,
-        capture_output=True,
-    )
-    uncompressed_file = run_result.stdout
-    self.assertEqual(file_contents, uncompressed_file)
+  def _TestStdoutCompressionFromFileImpl(self):
+    """Tests that compression of a file & outputting to stdout works.
+
+    Pixz has some semi-weird behavior here (b/202735786).
+    """
+    xz_auto_script = str(FindXzAutoLocation())
+    for file_contents in self.TEST_FILE_CONTENTS:
+      file_location = os.path.join(self.tempdir, 'file.txt')
+      osutils.WriteFile(file_location, file_contents, mode='wb')
+
+      run_result = cros_build_lib.run(
+          [
+              xz_auto_script,
+              '-c',
+              file_location,
+          ],
+          capture_output=True,
+      )
+
+      compressed_file = run_result.stdout
+      self.assertExists(file_location)
+      self.assertNotEqual(compressed_file, file_contents)
+
+      run_result = cros_build_lib.run(
+          [
+              xz_auto_script,
+              '--decompress',
+              '-c',
+          ],
+          capture_output=True,
+          input=compressed_file,
+      )
+      uncompressed_file = run_result.stdout
+      self.assertEqual(file_contents, uncompressed_file)
 
   @unittest.skipIf(not xz_auto.HasPixz(), 'need pixz for this test')
   def testFileCompressionWithPixzWorks(self):
     """Tests that compressing a file with pixz WAI."""
     self._TestFileCompressionImpl()
 
+    # We fall back to `xz` with small files. Make sure we actually cover the
+    # pixz case, too. We disable testing of empty inputs, since pixz breaks
+    # with those.
+    #
+    # cros_test_lib will clean this var up at the end of the test.
+    os.environ[xz_auto.XZ_DISABLE_VAR] = '1'
+    self._TestFileCompressionImpl(test_empty_file=False)
+
   @unittest.skipIf(not xz_auto.HasPixz(), 'need pixz for this test')
   def testStdoutCompressionWithPixzWorks(self):
     """Tests that compressing `stdout` with pixz WAI."""
     self._TestStdoutCompressionImpl()
 
+  @unittest.skipIf(not xz_auto.HasPixz(), 'need pixz for this test')
+  def testStdoutCompressionFromFileWithPixzWorks(self):
+    """Tests that compressing from a file to stdout with pixz WAI."""
+    self._TestStdoutCompressionFromFileImpl()
+
   def testFileCompressionWithXzWorks(self):
     """Tests that compressing a file with pixz WAI."""
     self.DisablePixzForCurrentTest()
@@ -152,3 +206,8 @@
     """Tests that compressing `stdout` with pixz WAI."""
     self.DisablePixzForCurrentTest()
     self._TestStdoutCompressionImpl()
+
+  def testStdoutCompressionFromFileWithXzWorks(self):
+    """Tests that compressing from a file to stdout WAI."""
+    self.DisablePixzForCurrentTest()
+    self._TestStdoutCompressionFromFileImpl()
diff --git a/sdk/etc/bash_completion.d/argcomplete.sh b/sdk/etc/bash_completion.d/argcomplete.sh
new file mode 100644
index 0000000..12cbb32
--- /dev/null
+++ b/sdk/etc/bash_completion.d/argcomplete.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+# Copyright 2021 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Find and source the bash completion script for Python argcomplete
+# if the script exists.
+# This search is hacky. It dynamically adapts to different paths between
+# Python versions. Ideally argcomplete can tell us the path directly, but
+# its tools don't yet support this.
+# See https://github.com/kislyuk/argcomplete/issues/364.
+argcomplete_path=$(find /usr/lib*/py*/site-packages/argcomplete \
+  -name python-argcomplete.sh | head -n 1)
+if [[ -n "${argcomplete_path}" ]]; then
+  source "${argcomplete_path}"
+fi
diff --git a/sdk/etc/bash_completion.d/cros b/sdk/etc/bash_completion.d/cros
index 63929bb..a1fafb1 100644
--- a/sdk/etc/bash_completion.d/cros
+++ b/sdk/etc/bash_completion.d/cros
@@ -283,12 +283,20 @@
 complete -o bashdefault -o default -F _complete_equery equery
 
 # Use equery completion for equery-$board for known boards
-_boardlist=$(cros_list_overlays | egrep "^.*/overlays/overlay-.*$" |
+_boardlist=$(/mnt/host/source/chromite/bin/cros_list_overlays |
+             egrep "^.*/overlays/overlay-.*$" |
              sed -n "s/.*overlay-//p")
 for board in $_boardlist; do
   complete -o bashdefault -o default -F _complete_equery equery-$board
 done
 
+# Source additional bash completion scripts.
+for f in /mnt/host/source/chromite/sdk/etc/bash_completion.d/*.sh; do
+  if [[ -f "${f}" ]]; then
+    source "$f"
+  fi
+done
+
 ###  Local Variables:
 ###  mode: shell-script
 ###  End:
diff --git a/sdk/etc/bash_completion.d/git.sh b/sdk/etc/bash_completion.d/git.sh
new file mode 120000
index 0000000..3f67a26
--- /dev/null
+++ b/sdk/etc/bash_completion.d/git.sh
@@ -0,0 +1 @@
+/usr/share/bash-completion/completions/git
\ No newline at end of file
diff --git a/sdk/etc/bash_completion.d/repo.sh b/sdk/etc/bash_completion.d/repo.sh
new file mode 120000
index 0000000..9ef71b6
--- /dev/null
+++ b/sdk/etc/bash_completion.d/repo.sh
@@ -0,0 +1 @@
+/mnt/host/source/.repo/repo/completion.bash
\ No newline at end of file
diff --git a/sdk/reclient_cfgs/README.md b/sdk/reclient_cfgs/README.md
new file mode 100644
index 0000000..babe6b6
--- /dev/null
+++ b/sdk/reclient_cfgs/README.md
@@ -0,0 +1,4 @@
+This directory contains the config files accepted by re-client's reproxy command.
+
+// TODO(crbug/1256966): For non-informational builds, these reproxy configs should
+// be generated by recipes instead of committed here.
diff --git a/sdk/reclient_cfgs/reproxy_informational.cfg b/sdk/reclient_cfgs/reproxy_informational.cfg
new file mode 100644
index 0000000..c273949
--- /dev/null
+++ b/sdk/reclient_cfgs/reproxy_informational.cfg
@@ -0,0 +1,5 @@
+service=remotebuildexecution.googleapis.com:443
+instance=projects/goma-foundry-experiments/instances/default_instance
+use_application_default_credentials=true
+server_address=unix:///tmp/reproxy.sock
+log_path=text:///tmp/reproxy_log.txt
\ No newline at end of file
diff --git a/service/android.py b/service/android.py
index 359db40..441bfdb 100644
--- a/service/android.py
+++ b/service/android.py
@@ -4,10 +4,12 @@
 
 """Provides utility for performing Android uprev."""
 
+import json
 import logging
 import os
 import re
 import time
+from typing import Dict, Optional, Tuple, Union
 
 from chromite.lib import constants
 from chromite.lib import gs
@@ -79,14 +81,33 @@
 ARC_BUCKET_ACL_PUBLIC = 'googlestorage_acl_public.txt'
 
 
-def GetAndroidBranchForPackage(android_package):
+# The overlay that hosts Android packages.
+OVERLAY_DIR = os.path.join(constants.SOURCE_ROOT, 'src', 'private-overlays',
+                           'project-cheets-private')
+
+
+def GetAndroidPackageDir(android_package: str,
+                         overlay_dir: str = OVERLAY_DIR) -> str:
+  """Returns the Portage package directory of the given Android package.
+
+  Args:
+    android_package: the Android package name e.g. 'android-vm-rvc'
+    overlay_dir: specify to override the default overlay.
+
+  Returns:
+    The Portage package directory
+  """
+  return os.path.join(overlay_dir, 'chromeos-base', android_package)
+
+
+def GetAndroidBranchForPackage(android_package: str) -> str:
   """Returns the corresponding Android branch of given Android package.
 
   Args:
-    android_package (str): the Android package name e.g. 'android-vm-rvc'
+    android_package: the Android package name e.g. 'android-vm-rvc'
 
   Returns:
-    str: the corresponding Android branch e.g. 'git_rvc-arc'
+    The corresponding Android branch e.g. 'git_rvc-arc'
   """
   mapping = {
       constants.ANDROID_PI_PACKAGE: constants.ANDROID_PI_BUILD_BRANCH,
@@ -100,7 +121,9 @@
     raise ValueError(f'Unknown Android package "{android_package}"')
 
 
-def IsBuildIdValid(build_branch, build_id, bucket_url=ANDROID_BUCKET_URL):
+def IsBuildIdValid(build_branch: str,
+                   build_id: str,
+                   bucket_url: str = ANDROID_BUCKET_URL) -> Optional[dict]:
   """Checks that a specific build_id is valid.
 
   Looks for that build_id for all builds. Confirms that the subpath can
@@ -130,11 +153,12 @@
           'Directory [%s] does not contain any subpath, ignoring it.',
           build_id_path)
       return None
+    # b/215041592: Sometimes there can be multiple subpaths which presumably
+    # contain the exact same artifacts.
     if len(subpaths) > 1:
       logging.warning(
-          'Directory [%s] contains more than one subpath, ignoring it.',
+          'Directory [%s] contains more than one subpath, using the first one.',
           build_id_path)
-      return None
 
     subpath_dir = subpaths[0].url.rstrip('/')
     subpath_name = os.path.basename(subpath_dir)
@@ -155,7 +179,10 @@
   return subpaths_dict
 
 
-def GetLatestBuild(build_branch, bucket_url=ANDROID_BUCKET_URL):
+def GetLatestBuild(
+    build_branch: str,
+    bucket_url: str = ANDROID_BUCKET_URL
+) -> Union[Tuple[None, None], Tuple[str, dict]]:
   """Searches the gs bucket for the latest green build.
 
   Args:
@@ -206,7 +233,7 @@
   return None, None
 
 
-def _GetAcl(target, package_dir):
+def _GetAcl(target: str, package_dir: str) -> str:
   """Returns the path to ACL file corresponding to target.
 
   Args:
@@ -225,8 +252,9 @@
   raise ValueError(f'Unknown target {target}')
 
 
-def CopyToArcBucket(android_bucket_url, build_branch, build_id, subpaths,
-                    arc_bucket_url, package_dir):
+def CopyToArcBucket(android_bucket_url: str, build_branch: str, build_id: str,
+                    subpaths: Dict[str, str], arc_bucket_url: str,
+                    package_dir: str) -> None:
   """Copies from source Android bucket to ARC++ specific bucket.
 
   Copies each build to the ARC bucket eliminating the subpath.
@@ -294,8 +322,11 @@
           break
 
 
-def MirrorArtifacts(android_bucket_url, android_build_branch, arc_bucket_url,
-                    package_dir, version=None):
+def MirrorArtifacts(android_bucket_url: str,
+                    android_build_branch: str,
+                    arc_bucket_url: str,
+                    package_dir: str,
+                    version: Optional[str] = None) -> Optional[str]:
   """Mirrors artifacts from Android bucket to ARC bucket.
 
   First, this function identifies which build version should be copied,
@@ -326,3 +357,59 @@
                   arc_bucket_url, package_dir)
 
   return version
+
+
+_LKGB_JSON = 'LKGB.json'
+
+
+class MissingLKGBError(Exception):
+  """LKGB file for the given Android package is missing."""
+
+
+class InvalidLKGBError(Exception):
+  """LKGB file for the given Android package contains invalid content."""
+
+
+def WriteLKGB(android_package_dir: str, build_id: str) -> str:
+  """Writes the LKGB file under the given Android package directory.
+
+  Args:
+    android_package_dir: The Android package directory.
+    build_id: The last known good Android build ID.
+
+  Returns:
+    Path to the updated file.
+  """
+  path = os.path.join(android_package_dir, _LKGB_JSON)
+  lkgb = {'build_id': build_id}
+  with open(path, 'w') as f:
+    json.dump(lkgb, f, indent=2)
+    f.write('\n')
+  return path
+
+
+def ReadLKGB(android_package_dir: str) -> str:
+  """Reads the LKGB file under the given Android package directory.
+
+  Args:
+    android_package_dir: The Android package directory.
+
+  Returns:
+    The last known good Android build ID as described in the file.
+
+  Raises:
+    MissingLKGBError: If the LKGB file is not found under android_package_dir.
+    InvalidLKGBError: If the LKGB file contains invalid content.
+  """
+  path = os.path.join(android_package_dir, _LKGB_JSON)
+  if not os.path.exists(path):
+    raise MissingLKGBError(path)
+
+  try:
+    with open(path, 'r') as f:
+      lkgb = json.load(f)
+    return lkgb['build_id']
+  except json.JSONDecodeError as e:
+    raise InvalidLKGBError('Error decoding LKGB file as JSON: ' + str(e))
+  except KeyError:
+    raise InvalidLKGBError('Field build_id not found in LKGB file')
diff --git a/service/android_unittest.py b/service/android_unittest.py
index 147d408..b9cd6b4 100644
--- a/service/android_unittest.py
+++ b/service/android_unittest.py
@@ -12,7 +12,6 @@
 from chromite.lib import gs
 from chromite.lib import gs_unittest
 from chromite.lib import osutils
-from chromite.lib import portage_util
 from chromite.service import android
 
 
@@ -69,9 +68,8 @@
     self.android_package = constants.ANDROID_PI_PACKAGE
 
     self.tmp_overlay = os.path.join(self.tempdir, 'chromiumos-overlay')
-    self.mock_android_dir = os.path.join(
-        self.tmp_overlay,
-        portage_util.GetFullAndroidPortagePackageName(self.android_package))
+    self.mock_android_dir = android.GetAndroidPackageDir(
+        self.android_package, overlay_dir=self.tmp_overlay)
 
     self.old_version = '25'
     self.old2_version = '50'
@@ -326,7 +324,7 @@
     self.assertEqual(subpaths['cheets_x86-user'], 'cheets_x86-user100')
     self.assertEqual(subpaths['cheets_x86_64-user'], 'cheets_x86_64-user100')
     self.assertEqual(subpaths['cheets_arm-userdebug'],
-                    'cheets_arm-userdebug100')
+                     'cheets_arm-userdebug100')
     self.assertEqual(subpaths['cheets_arm64-userdebug'],
                      'cheets_arm64-userdebug100')
     self.assertEqual(subpaths['cheets_x86-userdebug'],
@@ -343,3 +341,36 @@
     android.CopyToArcBucket(self.bucket_url, self.build_branch,
                             self.new_version, self.new_subpaths,
                             self.arc_bucket_url, self.mock_android_dir)
+
+
+class LKGBTest(cros_test_lib.TempDirTestCase):
+  """Tests ReadLKGB/WriteLKGB."""
+
+  def testWriteReadLGKB(self):
+    android_package_dir = self.tempdir
+    build_id = 'build-id'
+
+    android.WriteLKGB(android_package_dir, build_id)
+    self.assertEqual(android.ReadLKGB(android_package_dir), build_id)
+
+  def testReadLKGBMissing(self):
+    android_package_dir = self.tempdir
+
+    with self.assertRaises(android.MissingLKGBError):
+      android.ReadLKGB(android_package_dir)
+
+  def testReadLKGBNotJSON(self):
+    android_package_dir = self.tempdir
+    with open(os.path.join(android_package_dir, 'LKGB.json'), 'w') as f:
+      f.write('not-a-json-file')
+
+    with self.assertRaises(android.InvalidLKGBError):
+      android.ReadLKGB(android_package_dir)
+
+  def testReadLKGBMissingBuildID(self):
+    android_package_dir = self.tempdir
+    with open(os.path.join(android_package_dir, 'LKGB.json'), 'w') as f:
+      f.write('{"not_build_id": "foo"}')
+
+    with self.assertRaises(android.InvalidLKGBError):
+      android.ReadLKGB(android_package_dir)
diff --git a/service/artifacts.py b/service/artifacts.py
index 90f41e5..753b6fd 100644
--- a/service/artifacts.py
+++ b/service/artifacts.py
@@ -19,7 +19,6 @@
 from chromite.lib import cros_build_lib
 from chromite.lib import osutils
 from chromite.lib import portage_util
-from chromite.lib import toolchain_util
 from chromite.lib.paygen import partition_lib
 from chromite.lib.paygen import paygen_payload_lib
 from chromite.lib.paygen import paygen_stateful_payload_lib
@@ -571,53 +570,6 @@
   return payloads
 
 
-def BundleAFDOGenerationArtifacts(is_orderfile: bool,
-                                  chroot: 'chroot_lib.Chroot', chrome_root: str,
-                                  build_target: 'build_target_lib.BuildTarget',
-                                  output_dir: str) -> List[str]:
-  """Generate artifacts for toolchain-related AFDO artifacts.
-
-  Args:
-    is_orderfile: The generation is for orderfile (True) or for AFDO (False).
-    chroot: The chroot in which the sysroot should be built.
-    chrome_root: Path to Chrome root.
-    build_target: The build target.
-    output_dir: The location outside the chroot where the files should be
-      stored.
-
-  Returns:
-    The list of tarballs of artifacts.
-  """
-  chroot_args = chroot.get_enter_args()
-  with chroot.tempdir() as tempdir:
-    if is_orderfile:
-      generate_orderfile = toolchain_util.GenerateChromeOrderfile(
-          board=build_target.name,
-          output_dir=tempdir,
-          chrome_root=chrome_root,
-          chroot_path=chroot.path,
-          chroot_args=chroot_args)
-
-      generate_orderfile.Perform()
-    else:
-      generate_afdo = toolchain_util.GenerateBenchmarkAFDOProfile(
-          board=build_target.name,
-          output_dir=tempdir,
-          chroot_path=chroot.path,
-          chroot_args=chroot_args)
-
-      generate_afdo.Perform()
-
-    files = []
-    for path in osutils.DirectoryIterator(tempdir):
-      if os.path.isfile(path):
-        rel_path = os.path.relpath(path, tempdir)
-        files.append(os.path.join(output_dir, rel_path))
-    osutils.CopyDirContents(tempdir, output_dir, allow_nonempty=True)
-
-    return files
-
-
 def BundleTastFiles(chroot: 'chroot_lib.Chroot', sysroot: 'sysroot_lib.Sysroot',
                     output_dir: str) -> Optional[str]:
   """Tar up the Tast private test bundles.
diff --git a/service/artifacts_unittest.py b/service/artifacts_unittest.py
index a353ac7..ddaf2f7 100644
--- a/service/artifacts_unittest.py
+++ b/service/artifacts_unittest.py
@@ -20,7 +20,6 @@
 from chromite.lib import partial_mock
 from chromite.lib import portage_util
 from chromite.lib import sysroot_lib
-from chromite.lib import toolchain_util
 from chromite.lib.paygen import partition_lib
 from chromite.lib.paygen import paygen_payload_lib
 from chromite.lib.paygen import paygen_stateful_payload_lib
@@ -434,78 +433,6 @@
         tarball,
         unittest_files + ('bloonchipper/', 'dartmonkey/'))
 
-class BundleAFDOGenerationArtifacts(cros_test_lib.MockTempDirTestCase):
-  """BundleAFDOGenerationArtifacts tests."""
-
-  def setUp(self):
-    # Create the build target.
-    self.build_target = build_target_lib.BuildTarget('board')
-
-    # Create the chroot.
-    self.chroot_dir = os.path.join(self.tempdir, 'chroot')
-    self.chroot_tmp = os.path.join(self.chroot_dir, 'tmp')
-    osutils.SafeMakedirs(self.chroot_tmp)
-    self.chroot = chroot_lib.Chroot(path=self.chroot_dir)
-
-    # Create the output directory.
-    self.output_dir = os.path.join(self.tempdir, 'output_dir')
-    osutils.SafeMakedirs(self.output_dir)
-
-    self.chrome_root = os.path.join(self.tempdir, 'chrome_root')
-
-  def testRunSuccess(self):
-    """Generic function for testing success cases for different types."""
-
-    # Separate tempdir for the method itself.
-    call_tempdir = os.path.join(self.chroot_tmp, 'call_tempdir')
-    osutils.SafeMakedirs(call_tempdir)
-    self.PatchObject(osutils.TempDir, '__enter__', return_value=call_tempdir)
-
-    mock_orderfile_generate = self.PatchObject(
-        toolchain_util, 'GenerateChromeOrderfile',
-        autospec=True)
-
-    mock_afdo_generate = self.PatchObject(
-        toolchain_util, 'GenerateBenchmarkAFDOProfile',
-        autospec=True)
-
-    # Test both orderfile and AFDO.
-    for is_orderfile in [False, True]:
-      # Set up files in the tempdir since the command isn't being called to
-      # generate anything for it to handle.
-      files = ['artifact1', 'artifact2']
-      expected_files = [os.path.join(self.output_dir, f) for f in files]
-      for f in files:
-        osutils.Touch(os.path.join(call_tempdir, f))
-
-      created = artifacts.BundleAFDOGenerationArtifacts(
-          is_orderfile, self.chroot, self.chrome_root,
-          self.build_target, self.output_dir)
-
-      # Test right class is called with right arguments
-      if is_orderfile:
-        mock_orderfile_generate.assert_called_once_with(
-            board=self.build_target.name,
-            chrome_root=self.chrome_root,
-            output_dir=call_tempdir,
-            chroot_path=self.chroot.path,
-            chroot_args=self.chroot.get_enter_args()
-        )
-      else:
-        mock_afdo_generate.assert_called_once_with(
-            board=self.build_target.name,
-            output_dir=call_tempdir,
-            chroot_path=self.chroot.path,
-            chroot_args=self.chroot.get_enter_args(),
-        )
-
-      # Make sure we get all the expected files
-      self.assertCountEqual(expected_files, created)
-      for f in created:
-        self.assertExists(f)
-        os.remove(f)
-
-
 class GeneratePayloadsTest(cros_test_lib.MockTempDirTestCase):
   """Test cases for the payload generation functions."""
 
diff --git a/service/binhost.py b/service/binhost.py
index 8239ca4..2378b0e 100644
--- a/service/binhost.py
+++ b/service/binhost.py
@@ -41,7 +41,7 @@
   """No ACL file could be found."""
 
 
-def _ValidateBinhostConf(path, key):
+def _ValidateBinhostConf(path: str, key: str) -> None:
   """Validates the binhost conf file defines only one environment variable.
 
   This function is effectively a sanity check that ensures unexpected
@@ -70,7 +70,8 @@
     raise KeyError('Did not find key %s in %s' % (key, path))
 
 
-def _ValidatePrebuiltsFiles(prebuilts_root, prebuilts_paths):
+def _ValidatePrebuiltsFiles(prebuilts_root: str,
+                            prebuilts_paths: List[str]) -> None:
   """Validate all prebuilt files exist.
 
   Args:
@@ -86,7 +87,8 @@
       raise LookupError('Prebuilt archive %s does not exist' % full_path)
 
 
-def _ValidatePrebuiltsRoot(target, prebuilts_root):
+def _ValidatePrebuiltsRoot(target: 'build_target_lib.BuildTarget',
+                           prebuilts_root: str) -> None:
   """Validate the given prebuilts root exists.
 
   If the root does not exist, it probably means the build target did not build
@@ -330,7 +332,7 @@
                                package_index_path: str,
                                upload_uri: str,
                                upload_path: str,
-                               sudo: bool = False):
+                               sudo: bool = False) -> None:
   """Create Package file for dev-install process.
 
   The created package file (package_index_path) contains only the
@@ -347,11 +349,11 @@
     sudo: Whether to write the file as the root user.
   """
 
-  def ShouldFilterPackage(package):
+  def ShouldFilterPackage(package: dict) -> bool:
     """Local func to filter packages not in the devinstall_package_list
 
     Args:
-      package (dict): Dictionary with key 'CPV' and package name as value
+      package: Dictionary with key 'CPV' and package name as value
 
     Returns:
       True (filter) if not in the devinstall_package_list, else False (don't
diff --git a/service/dependency.py b/service/dependency.py
index 13555b7..6503504 100644
--- a/service/dependency.py
+++ b/service/dependency.py
@@ -8,7 +8,7 @@
 import itertools
 import os
 from pathlib import Path
-from typing import List, Mapping, Optional
+from typing import Collection, List, Mapping, Optional, Set, Tuple, TYPE_CHECKING
 
 from chromite.lib import build_target_lib
 from chromite.lib import constants
@@ -20,6 +20,9 @@
 if cros_build_lib.IsInsideChroot():
   from chromite.lib import depgraph
 
+if TYPE_CHECKING:
+  from chromite.lib.dependency_graph import PackageNode
+  from chromite.lib.parser.package_info import PackageInfo
 
 class Error(Exception):
   """Base error class for the module."""
@@ -61,7 +64,7 @@
 
   Returns:
     Map from each package to the source path (relative to the repo checkout
-      root, i.e: ~/trunk/ in your cros_sdk) it depends on.
+      root, i.e: ~/chromiumos/ in your cros_sdk) it depends on.
     For each source path which is a directory, the string is ended with a
       trailing '/'.
   """
@@ -83,25 +86,29 @@
   assert sysroot_path
   return dependency_lib.get_source_path_mapping(packages, sysroot_path, board)
 
+# TODO(b/187794810): Update this type annotation to use TypedDict once we have
+#                    Python 3.8 or newer.
 
 @functools.lru_cache()
-def GetBuildDependency(sysroot_path, board=None, packages=None):
+def GetBuildDependency(
+    sysroot_path: Optional[str],
+    board: Optional[str] = None,
+    packages: Optional[Collection['PackageInfo']] = None) -> Tuple[dict, dict]:
   """Return the build dependency and package -> source path map for |board|.
 
   Args:
-    sysroot_path (str): The path to the sysroot, or None if no sysroot is being
-        used.
-    board (str): The name of the board whose artifacts are being created, or
-        None if no sysroot is being used.
-    packages (tuple[CPV]): The packages that need to be built, or empty / None
-        to use the default list.
+    sysroot_path: The path to the sysroot, or None if no sysroot is being used.
+    board: The name of the board whose artifacts are being created, or None if
+        no sysroot is being used.
+    packages: The packages that need to be built, or empty / None to use the
+        default list.
 
   Returns:
     JSON build dependencies report for the given board which includes:
       - Package level deps graph from portage
       - Map from each package to the source path
-      (relative to the repo checkout root, i.e: ~/trunk/ in your cros_sdk) it
-      depends on
+      (relative to the repo checkout root, i.e: ~/chromiumos/ in your cros_sdk)
+      it depends on
   """
   if not sysroot_path:
     sysroot_path = build_target_lib.get_default_sysroot_path(board)
@@ -195,10 +202,11 @@
   return False
 
 
-def GetDependencies(sysroot_path: str,
-                    src_paths: Optional[List[str]] = None,
-                    packages: Optional[List[str]] = None,
-                    include_rev_dependencies: bool = False) -> List[str]:
+def GetDependencies(
+    sysroot_path: str,
+    src_paths: Optional[Collection[str]] = None,
+    packages: Optional[Collection[str]] = None,
+    include_rev_dependencies: bool = False) -> Set['PackageInfo']:
   """Return the packages dependent on the given source paths for |board|.
 
   Args:
@@ -215,22 +223,21 @@
       src_paths.
   """
   cros_build_lib.AssertInsideChroot()
-  pkgs = tuple(packages) if packages else None
   dep_graph = depgraph.get_sysroot_dependency_graph(
-      sysroot_path, pkgs, with_src_paths=True)
+      sysroot_path, packages, with_src_paths=True)
 
   if not src_paths:
-    return [x.pkg_info for x in dep_graph.get_nodes()]
+    return set(x.pkg_info for x in dep_graph.get_nodes())
 
   dep_nodes = dep_graph.get_relevant_nodes(src_paths=src_paths)
-  rev_dep_nodes = []
+  rev_dep_nodes: List['PackageNode'] = []
   if include_rev_dependencies:
     for dep in dep_nodes:
       rev_dep_nodes.extend(dep.reverse_dependencies)
-  return list({dep.pkg_info for dep in dep_nodes + rev_dep_nodes})
+  return set(dep.pkg_info for dep in dep_nodes + rev_dep_nodes)
 
 
-def DetermineToolchainSourcePaths():
+def DetermineToolchainSourcePaths() -> List[str]:
   """Returns a list of all source paths relevant to toolchain packages.
 
   A package is a 'toolchain package' if it is listed as a direct dependency
@@ -243,7 +250,7 @@
   Returned paths are relative to the root of the project checkout.
 
   Returns:
-    List[str]: A list of paths considered relevant to toolchain packages.
+    A list of paths considered relevant to toolchain packages.
   """
   source_paths = set()
   toolchain_pkgs = portage_util.GetFlattenedDepsForPackage(
diff --git a/service/image.py b/service/image.py
index 9c38879..b6f15a9 100644
--- a/service/image.py
+++ b/service/image.py
@@ -323,17 +323,20 @@
   return os.path.realpath(vm_path)
 
 
-def CreateGuestVm(board, is_test=False, chroot=None, image_dir=None):
+def CreateGuestVm(board: str,
+                  is_test: bool = False,
+                  chroot: chroot_lib.Chroot = None,
+                  image_dir: str = None) -> str:
   """Convert an existing image into a guest VM image.
 
   Args:
-    board (str): The name of the board to convert.
-    is_test (bool): Flag to create a test guest VM image.
-    chroot (chroot_lib.Chroot): The chroot where the cros image lives.
+    board: The name of the board to convert.
+    is_test: Flag to create a test guest VM image.
+    chroot: The chroot where the cros image lives.
     image_dir: The directory containing the built images.
 
   Returns:
-    str: Path to the created guest VM folder.
+    Path to the created guest VM folder.
   """
   assert board
 
@@ -432,20 +435,22 @@
   return license_credits_dest_path
 
 
-def Test(board, result_directory, image_dir=None):
+def Test(board: str,
+         result_directory: str,
+         image_dir: str = None) -> bool:
   """Run tests on an already built image.
 
   Currently this is just running test_image.
 
   Args:
-    board (str): The board name.
-    result_directory (str): Root directory where the results should be stored
+    board: The board name.
+    result_directory: Root directory where the results should be stored
       relative to the chroot.
-    image_dir (str): The path to the image. Uses the board's default image
+    image_dir: The path to the image. Uses the board's default image
       build path when not provided.
 
   Returns:
-    bool - True if all tests passed, False otherwise.
+    True if all tests passed, False otherwise.
   """
   if not board:
     raise InvalidArgumentError('Board is required.')
@@ -473,18 +478,17 @@
 
   return result.returncode == 0
 
-def create_factory_image_zip(
-  chroot: chroot_lib.Chroot,
-  sysroot_class: sysroot_lib.Sysroot,
-  factory_shim_dir: Path,
-  version: str,
-  output_dir: str) -> Union[str, None]:
+def create_factory_image_zip(chroot: chroot_lib.Chroot,
+                             sysroot_class: sysroot_lib.Sysroot,
+                             factory_shim_dir: Path,
+                             version: str,
+                             output_dir: str) -> Union[str, None]:
   """Build factory_image.zip in archive_dir.
 
   Args:
     chroot: The chroot class used for these artifacts.
-    sysroot_class (sysroot_lib.Sysroot): The sysroot where the original
-      environment archive can be found.
+    sysroot_class: The sysroot where the original environment archive
+      can be found.
     factory_shim_dir: Directory containing factory shim.
     version: if not None, version to include in factory_image.zip
     output_dir: Directory to store factory_image.zip.
@@ -501,14 +505,14 @@
     logging.error('create_factory_image_zip: %s not found', factory_shim_dir)
     return None
   files = ['*factory_install*.bin', '*partition*',
-            os.path.join('netboot', '*')]
+           os.path.join('netboot', '*')]
   cmd_files = []
   for file in files:
     cmd_files.extend(['--include', os.path.join(factory_shim_dir.name, file)])
   # factory_shim_dir may be a symlink. We can not use '-y' here.
   cros_build_lib.run(cmd + [factory_shim_dir.name] + cmd_files,
-                      cwd=factory_shim_dir.parent,
-                      capture_output=True)
+                     cwd=factory_shim_dir.parent,
+                     capture_output=True)
 
   # Everything in /usr/local/factory/bundle gets overlaid into the
   # bundle.
diff --git a/service/packages.py b/service/packages.py
index bd50ee7..08fe9c4 100644
--- a/service/packages.py
+++ b/service/packages.py
@@ -13,7 +13,7 @@
 import os
 import re
 import sys
-from typing import List, Optional, TYPE_CHECKING, Union
+from typing import Iterable, List, NamedTuple, Optional, TYPE_CHECKING, Union
 
 from chromite.third_party.google.protobuf import json_format
 
@@ -28,9 +28,11 @@
 from chromite.lib import replication_lib
 from chromite.lib import uprev_lib
 from chromite.lib.parser import package_info
+from chromite.service import android
 
 if TYPE_CHECKING:
   from chromite.lib import build_target_lib
+  from chromite.lib import chroot_lib
 
 if cros_build_lib.IsInsideChroot():
   from chromite.lib import depgraph
@@ -139,13 +141,38 @@
   return register
 
 
-def uprev_android(android_package,
-                  chroot,
-                  build_targets=None,
-                  android_build_branch=None,
-                  android_version=None,
-                  skip_commit=False):
-  """Returns the portage atom for the revved Android ebuild - see man emerge."""
+class UprevAndroidResult(NamedTuple):
+  """Results of an Android uprev."""
+  revved: bool
+  android_atom: str = None
+  modified_files: List[str] = None
+
+
+def uprev_android(
+    android_package: str,
+    chroot: 'chroot_lib.Chroot',
+    build_targets: Optional[List['build_target_lib.BuildTarget']] = None,
+    android_build_branch: Optional[str] = None,
+    android_version: Optional[str] = None,
+    skip_commit: bool = False) -> UprevAndroidResult:
+  """Performs an Android uprev by calling cros_mark_android_as_stable.
+
+  Args:
+    android_package: The Android package to uprev.
+    chroot: The chroot to enter.
+    build_targets: List of build targets to cleanup after uprev.
+    android_build_branch: Override the default Android branch corresponding to
+        the package.
+    android_version: Uprev to the particular version. By default the latest
+        available version is used.
+    skip_commit: Whether to skip committing the change after a successful uprev.
+
+  Returns:
+    The uprev result containing:
+      revved: Whether an uprev happened.
+      android_atom: If revved, the portage atom for the revved Android ebuild.
+      modified_files: If revved, list of files being modified.
+  """
   command = [
       'cros_mark_android_as_stable',
       f'--android_package={android_package}',
@@ -166,13 +193,17 @@
       encoding='utf-8',
       chroot_args=chroot.get_enter_args())
 
-  portage_atom_string = result.stdout.strip()
-  android_atom = None
-  if portage_atom_string:
-    android_atom = portage_atom_string.splitlines()[-1].partition('=')[-1]
-  if not android_atom:
+  # cros_mark_android_as_stable prints the uprev result to stdout as JSON in a
+  # single line. We only take the last line from stdout to make sure no junk
+  # output is included (e.g. messages from bashrc scripts that run upon entering
+  # the chroot.)
+  output = json.loads(result.stdout.strip().splitlines()[-1])
+
+  if not output['revved']:
     logging.info('Found nothing to rev.')
-    return None
+    return UprevAndroidResult(revved=False)
+
+  android_atom = output['android_atom']
 
   for target in build_targets or []:
     # Sanity check: We should always be able to merge the version of
@@ -187,22 +218,83 @@
           'version?', target, android_atom)
       raise AndroidIsPinnedUprevError(android_atom)
 
-  return android_atom
+  return UprevAndroidResult(revved=True,
+                            android_atom=android_atom,
+                            modified_files=output['modified_files'])
 
 
-def uprev_build_targets(build_targets,
-                        overlay_type,
-                        chroot=None,
-                        output_dir=None):
+def uprev_android_lkgb(android_package: str,
+                       build_targets: List['build_target_lib.BuildTarget'],
+                       chroot: 'chroot_lib.Chroot'
+                       ) -> uprev_lib.UprevVersionedPackageResult:
+  """Uprevs an Android package to the version specified in the LKGB file.
+
+  This is the PUpr handler for Android packages, triggered whenever the
+  corresponding LKGB file is being updated.
+
+  PUpr for Android does not test the uprev change in CQ; instead we run separate
+  jobs to test new Android versions, and we write the latest vetted version to
+  the LKGB file. Find the design at go/android-uprev-recipes.
+
+  Args:
+    android_package: The Android package to uprev.
+    build_targets: List of build targets to cleanup after uprev.
+    chroot: The chroot to enter.
+
+  Returns:
+    An uprev_lib.UprevVersionedPackageResult containing the new version and a
+    list of modified files.
+  """
+  android_package_dir = android.GetAndroidPackageDir(android_package)
+  android_version = android.ReadLKGB(android_package_dir)
+
+  result = uprev_lib.UprevVersionedPackageResult()
+  uprev_result = uprev_android(android_package, chroot,
+                               build_targets=build_targets,
+                               android_version=android_version,
+                               skip_commit=True)
+  if not uprev_result.revved:
+    return result
+
+  # cros_mark_android_as_stable returns paths relative to |android.OVERLAY_DIR|.
+  result.add_result(android_version,
+                    [os.path.join(android.OVERLAY_DIR, f)
+                     for f in uprev_result.modified_files])
+  return result
+
+
+def define_uprev_android_lkgb_handlers():
+  """Dynamically define uprev handlers for each Android package"""
+
+  def define_handler(android_package):
+    """Defines the uprev handler for an Android package."""
+    full_package_name = 'chromeos-base/' + android_package
+
+    @uprevs_versioned_package(full_package_name)
+    def _handler(build_targets, _refs, chroot):
+      return uprev_android_lkgb(android_package, build_targets, chroot)
+
+  for android_package in constants.ANDROID_ALL_PACKAGES:
+    define_handler(android_package)
+
+
+define_uprev_android_lkgb_handlers()
+
+
+def uprev_build_targets(
+    build_targets: Optional[List['build_target_lib.BuildTarget']],
+    overlay_type: str,
+    chroot: 'chroot_lib.Chroot' = None,
+    output_dir: Optional[str] = None):
   """Uprev the set provided build targets, or all if not specified.
 
   Args:
-    build_targets (list[build_target_lib.BuildTarget]|None): The build targets
+    build_targets: The build targets
       whose overlays should be uprevved, empty or None for all.
-    overlay_type (str): One of the valid overlay types except None (see
+    overlay_type: One of the valid overlay types except None (see
       constants.VALID_OVERLAYS).
-    chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
-    output_dir (str|None): The path to optionally dump result files.
+    chroot: The chroot to clean, if desired.
+    output_dir: The path to optionally dump result files.
   """
   # Need a valid overlay, but exclude None.
   assert overlay_type and overlay_type in constants.VALID_OVERLAYS
@@ -220,20 +312,24 @@
       output_dir=output_dir)
 
 
-def uprev_overlays(overlays, build_targets=None, chroot=None, output_dir=None):
+def uprev_overlays(
+    overlays: List[str],
+    build_targets: Optional[List['build_target_lib.BuildTarget']] = None,
+    chroot: Optional['chroot_lib.Chroot'] = None,
+    output_dir: Optional[str] = None) -> List[str]:
   """Uprev the given overlays.
 
   Args:
-    overlays (list[str]): The list of overlay paths.
-    build_targets (list[build_target_lib.BuildTarget]|None): The build targets
+    overlays: The list of overlay paths.
+    build_targets: The build targets
       to clean in |chroot|, if desired. No effect unless |chroot| is provided.
-    chroot (chroot_lib.Chroot|None): The chroot to clean, if desired.
-    output_dir (str|None): The path to optionally dump result files.
+    chroot: The chroot to clean, if desired.
+    output_dir: The path to optionally dump result files.
 
   Returns:
-    list[str] - The paths to all of the modified ebuild files. This includes the
-      new files that were added (i.e. the new versions) and all of the removed
-      files (i.e. the old versions).
+    The paths to all of the modified ebuild files. This includes the new files
+      that were added (i.e. the new versions) and all of the removed files
+      (i.e. the old versions).
   """
   assert overlays
 
@@ -250,18 +346,21 @@
   return uprev_manager.modified_ebuilds, uprev_manager.revved_packages
 
 
-def uprev_versioned_package(package, build_targets, refs, chroot):
+def uprev_versioned_package(
+    package: package_info.CPV,
+    build_targets: List['build_target_lib.BuildTarget'],
+    refs: List[uprev_lib.GitRef],
+    chroot: 'chroot_lib.Chroot') -> 'uprev_lib.UprevVersionedPackageResult':
   """Call registered uprev handler function for the package.
 
   Args:
-    package (package_info.CPV): The package being uprevved.
-    build_targets (list[build_target_lib.BuildTarget]): The build targets to
-        clean on a successful uprev.
-    refs (list[uprev_lib.GitRef]):
-    chroot (chroot_lib.Chroot): The chroot to enter for cleaning.
+    package: The package being uprevved.
+    build_targets: The build targets to clean on a successful uprev.
+    refs:
+    chroot: The chroot to enter for cleaning.
 
   Returns:
-    UprevVersionedPackageResult: The result.
+    The result.
   """
   assert package
 
@@ -331,21 +430,6 @@
   if not uprev_result:
     return result
   all_changed_files.extend(uprev_result.changed_files)
-
-  # Attempt to uprev drivefs-ipc package.
-  pkg_path = os.path.join(DRIVEFS_PATH_PREFIX, 'drivefs-ipc')
-  uprev_result = uprev_lib.uprev_workon_ebuild_to_version(pkg_path,
-                                                          drivefs_version,
-                                                          chroot,
-                                                          allow_downrev=False)
-
-  if not uprev_result:
-    logging.warning(
-        'drivefs package has changed files %s but drivefs-ipc does not',
-        all_changed_files)
-    return result
-
-  all_changed_files.extend(uprev_result.changed_files)
   result.add_result(drivefs_version, all_changed_files)
 
   return result
@@ -430,20 +514,32 @@
 
 
 @uprevs_versioned_package('chromeos-base/termina-dlc')
-def uprev_termina_dlc(_build_targets, _refs, chroot):
-  """Updates shared termina-dlc ebuild - chromeos-base/termina-dlc.
+@uprevs_versioned_package('chromeos-base/termina-tools-dlc')
+def uprev_termina_dlcs(_build_targets, _refs, chroot):
+  """Updates shared termina-dlc and termina-tools-dlc ebuilds.
+
+  termina-dlc - chromeos-base/termina-dlc
+  termina-tools-dlc - chromeos-base/termina-tools-dlc
 
   See: uprev_versioned_package.
   """
-  package = 'termina-dlc'
-  package_path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base',
-                              package)
+  termina_dlc_pkg = 'termina-dlc'
+  termina_dlc_pkg_path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR,
+                                      'chromeos-base', termina_dlc_pkg)
+  tools_dlc_pkg = 'termina-tools-dlc'
+  tools_dlc_pkg_path = os.path.join(constants.CHROMIUMOS_OVERLAY_DIR,
+                                    'chromeos-base', tools_dlc_pkg)
 
-  version_pin_src_path = _get_version_pin_src_path(package_path)
+  # termina-dlc and termina-tools-dlc are pinned to the same version.
+  version_pin_src_path = _get_version_pin_src_path(termina_dlc_pkg_path)
   version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
 
-  return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
+  result = uprev_lib.uprev_ebuild_from_pin(termina_dlc_pkg_path, version_no_rev,
+                                           chroot)
+  result += uprev_lib.uprev_ebuild_from_pin(tools_dlc_pkg_path, version_no_rev,
+                                            chroot)
 
+  return result
 
 @uprevs_versioned_package('chromeos-base/chromeos-lacros')
 def uprev_lacros(_build_targets, refs, chroot):
@@ -471,6 +567,39 @@
   return result
 
 
+@uprevs_versioned_package('chromeos-base/chromeos-lacros-parallel')
+def uprev_lacros_in_parallel(
+    _build_targets: Optional[List['build_target_lib.BuildTarget']],
+    refs: List[uprev_lib.GitRef],
+    chroot: 'chroot_lib.Chroot') -> 'uprev_lib.UprevVersionedPackageResult':
+  """Updates lacros ebuilds in parallel with ash-chrome.
+
+  This handler is going to be used temporarily while lacros transitions to being
+  uprevved atomically with ash-chrome. Unlike a standalone lacros uprev, this
+  handler will not need to look at the QA qualified file. Rather, it will
+  function identical to ash-chrome using git tags.
+
+  See: uprev_versioned_package.
+
+  Returns:
+    UprevVersionedPackageResult: The result.
+  """
+  result = uprev_lib.UprevVersionedPackageResult()
+  path = os.path.join(
+      constants.CHROMIUMOS_OVERLAY_DIR, 'chromeos-base', 'chromeos-lacros')
+  lacros_version = uprev_lib.get_version_from_refs(refs)
+  uprev_result = uprev_lib.uprev_workon_ebuild_to_version(path,
+                                                          lacros_version,
+                                                          chroot,
+                                                          allow_downrev=False)
+
+  if not uprev_result:
+    return result
+
+  result.add_result(lacros_version, uprev_result.changed_files)
+  return result
+
+
 @uprevs_versioned_package('app-emulation/parallels-desktop')
 def uprev_parallels_desktop(_build_targets, _refs, chroot):
   """Updates Parallels Desktop ebuild - app-emulation/parallels-desktop.
@@ -532,27 +661,43 @@
   return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
 
 
+@uprevs_versioned_package('chromeos-base/borealis-dlc')
+def uprev_borealis_dlc(_build_targets, _refs, chroot):
+  """Updates shared borealis-dlc ebuild - chromeos-base/borealis-dlc.
+
+  See: uprev_versioned_package.
+  """
+  package_path = os.path.join('src', 'private-overlays',
+                              'chromeos-partner-overlay', 'chromeos-base',
+                              'borealis-dlc')
+
+  version_pin_src_path = _get_version_pin_src_path(package_path)
+  version_no_rev = osutils.ReadFile(version_pin_src_path).strip()
+
+  return uprev_lib.uprev_ebuild_from_pin(package_path, version_no_rev, chroot)
+
+
 def _get_version_pin_src_path(package_path):
   """Returns the path to the VERSION-PIN file for the given package."""
   return os.path.join(constants.SOURCE_ROOT, package_path, 'VERSION-PIN')
 
 
 @uprevs_versioned_package(constants.CHROME_CP)
-def uprev_chrome_from_ref(build_targets, refs, chroot):
+def uprev_chrome_from_ref(build_targets, refs, _chroot):
   """Uprev chrome and its related packages.
 
   See: uprev_versioned_package.
   """
   # Determine the version from the refs (tags), i.e. the chrome versions are the
   # tag names.
-  chrome_version = uprev_lib.get_chrome_version_from_refs(refs)
+  chrome_version = uprev_lib.get_version_from_refs(refs)
   logging.debug('Chrome version determined from refs: %s', chrome_version)
 
-  return uprev_chrome(build_targets, chrome_version, chroot)
+  return uprev_chrome(chrome_version, build_targets, None)
 
 
 def revbump_chrome(
-    build_targets: List['build_target_lib.BuildTarget'],
+    build_targets: List['build_target_lib.BuildTarget'] = None,
     chroot: Optional['chroot_lib.Chroot'] = None
 ) -> uprev_lib.UprevVersionedPackageResult:
   """Attempt to revbump chrome.
@@ -563,12 +708,13 @@
   ebuild) will result in a revbump to 1.2.3.4_rc-r3.ebuild.
   """
   chrome_version = uprev_lib.get_stable_chrome_version()
-  return uprev_chrome(build_targets, chrome_version, chroot)
+  return uprev_chrome(chrome_version, build_targets, chroot)
 
 
 def uprev_chrome(
-    build_targets: List['build_target_lib.BuildTarget'], chrome_version: str,
-    chroot: Union['chroot_lib.Chroot', None]
+    chrome_version: str,
+    build_targets: Optional[List['build_target_lib.BuildTarget']],
+    chroot: Optional['chroot_lib.Chroot']
 ) -> uprev_lib.UprevVersionedPackageResult:
   """Attempt to uprev chrome and its related packages to the given version."""
   uprev_manager = uprev_lib.UprevChromeManager(
@@ -636,15 +782,16 @@
   return target_version_ref.replace(refs_prefix, '')
 
 
-def _generate_platform_c_files(replication_config, chroot):
+def _generate_platform_c_files(
+    replication_config: replication_config_pb2.ReplicationConfig,
+    chroot: 'chroot_lib.Chroot') -> List[str]:
   """Generates platform C files from a platform JSON payload.
 
   Args:
-    replication_config (replication_config_pb2.ReplicationConfig): A
-      ReplicationConfig that has already been run. If it produced a
-      build_config.json file, that file will be used to generate platform C
-      files. Otherwise, nothing will be generated.
-    chroot (chroot_lib.Chroot): The chroot to use to generate.
+    replication_config: A ReplicationConfig that has already been run. If it
+      produced a build_config.json file, that file will be used to generate
+      platform C files. Otherwise, nothing will be generated.
+    chroot: The chroot to use to generate.
 
   Returns:
     A list of generated files.
@@ -703,12 +850,12 @@
   return generated_files
 
 
-def _get_private_overlay_package_root(ref, package):
+def _get_private_overlay_package_root(ref: uprev_lib.GitRef, package: str):
   """Returns the absolute path to the root of a given private overlay.
 
   Args:
-    ref (uprev_lib.GitRef): GitRef for the private overlay.
-    package (str): Path to the package in the overlay.
+    ref: GitRef for the private overlay.
+    package: Path to the package in the overlay.
   """
   # There might be a cleaner way to map from package -> path within the source
   # tree. For now, just use string patterns.
@@ -839,18 +986,21 @@
       sysroot=build_target.root if build_target else None)
 
 
-def has_prebuilt(atom, build_target=None, useflags=None):
+def has_prebuilt(
+    atom: str,
+    build_target: 'build_target_lib.BuildTarget' = None,
+    useflags: Union[Iterable[str], str] = None) -> bool:
   """Check if a prebuilt exists.
 
   Args:
-    atom (str): The package whose prebuilt is being queried.
-    build_target (build_target_lib.BuildTarget): The build target whose
-        sysroot should be searched, or the SDK if not provided.
+    atom: The package whose prebuilt is being queried.
+    build_target: The build target whose sysroot should be searched, or the
+        SDK if not provided.
     useflags: Any additional USE flags that should be set. May be a string
         of properly formatted USE flags, or an iterable of individual flags.
 
   Returns:
-    bool: True iff there is an available prebuilt, False otherwise.
+    True if there is an available prebuilt, False otherwise.
   """
   assert atom
 
@@ -944,14 +1094,61 @@
   )
 
 
-def determine_chrome_version(build_target):
+class TargetVersions(NamedTuple):
+  """Data class for the info that makes up the "target versions"."""
+  android_version: str
+  android_branch: str
+  android_target: str
+  chrome_version: str
+  platform_version: str
+  milestone_version: str
+  full_version: str
+
+
+def get_target_versions(
+    build_target: 'build_target_lib.BuildTarget',
+    packages: List[package_info.PackageInfo] = None
+) -> TargetVersions:
+  """Aggregate version info for a few key packages and the OS as a whole."""
+  # Android version.
+  android_version = determine_android_version(build_target.name)
+  logging.info('Found android version: %s', android_version)
+  # Android branch version.
+  android_branch = determine_android_branch(build_target.name)
+  logging.info('Found android branch version: %s', android_branch)
+  # Android target version.
+  android_target = determine_android_target(build_target.name)
+  logging.info('Found android target version: %s', android_target)
+
+  # TODO(crbug/1019770): Investigate cases where builds_chrome is true but
+  # chrome_version is None.
+
+  builds_chrome = builds(constants.CHROME_CP, build_target, packages=packages)
+  chrome_version = None
+  if builds_chrome:
+    # Chrome version fetch.
+    chrome_version = determine_chrome_version(build_target)
+    logging.info('Found chrome version: %s', chrome_version)
+
+  # The ChromeOS version info.
+  platform_version = determine_platform_version()
+  milestone_version = determine_milestone_version()
+  full_version = determine_full_version()
+
+  return TargetVersions(android_version, android_branch, android_target,
+                        chrome_version, platform_version, milestone_version,
+                        full_version)
+
+
+def determine_chrome_version(
+    build_target: 'build_target_lib.BuildTarget') -> Optional[str]:
   """Returns the current Chrome version for the board (or in buildroot).
 
   Args:
-    build_target (build_target_lib.BuildTarget): The board build target.
+    build_target: The board build target.
 
   Returns:
-    str|None: The chrome version if available.
+    The chrome version if available.
   """
   # TODO(crbug/1019770): Long term we should not need the try/catch here once
   # the builds function above only returns True for chrome when
@@ -968,14 +1165,15 @@
   return pkg_info.version.partition('_')[0]
 
 
-def determine_android_package(board):
+@functools.lru_cache()
+def determine_android_package(board: str) -> Optional[str]:
   """Returns the active Android container package in use by the board.
 
   Args:
     board: The board name this is specific to.
 
   Returns:
-    str|None: The android package string if there is one.
+    The android package string if there is one.
   """
   try:
     packages = portage_util.GetPackageDependencies(board, 'virtual/target-os')
@@ -993,7 +1191,7 @@
   return None
 
 
-def determine_android_version(board, package=None):
+def determine_android_version(board: str, package: str = None):
   """Determine the current Android version in buildroot now and return it.
 
   This uses the typical portage logic to determine which version of Android
@@ -1079,14 +1277,15 @@
   return full_version
 
 
-def find_fingerprints(build_target):
+def find_fingerprints(
+    build_target: 'build_target_lib.BuildTarget') -> List[str]:
   """Returns a list of fingerprints for this build.
 
   Args:
-    build_target (build_target_lib.BuildTarget): The build target.
+    build_target: The build target.
 
   Returns:
-    list[str] - List of fingerprint strings.
+    List of fingerprint strings.
   """
   cros_build_lib.AssertInsideChroot()
   fp_file = 'cheets-fingerprint.txt'
@@ -1101,11 +1300,11 @@
   return fingerprints
 
 
-def get_all_firmware_versions(build_target):
+def get_all_firmware_versions(build_target: 'build_target_lib.BuildTarget'):
   """Extract firmware version for all models present.
 
   Args:
-    build_target (build_target_lib.BuildTarget): The build target.
+    build_target: The build target.
 
   Returns:
     A dict of FirmwareVersions namedtuple instances by model.
@@ -1118,24 +1317,34 @@
   # in the packages_unittest.py for testing get_all_firmware_versions.
   cmd_result = _get_firmware_version_cmd_result(build_target)
 
-  # There is a blank line between the version info for each model.
-  firmware_version_payloads = cmd_result.split('\n\n')
-  for firmware_version_payload in firmware_version_payloads:
-    if 'BIOS' in firmware_version_payload:
-      firmware_version = _find_firmware_versions(firmware_version_payload)
-      result[firmware_version.model] = firmware_version
+  if cmd_result:
+    # There is a blank line between the version info for each model.
+    firmware_version_payloads = cmd_result.split('\n\n')
+    for firmware_version_payload in firmware_version_payloads:
+      if 'BIOS' in firmware_version_payload:
+        firmware_version = _find_firmware_versions(firmware_version_payload)
+        result[firmware_version.model] = firmware_version
   return result
 
 
-FirmwareVersions = collections.namedtuple(
-    'FirmwareVersions', ['model', 'main', 'main_rw', 'ec', 'ec_rw'])
+class FirmwareVersions(NamedTuple):
+  """Tuple to hold firmware versions, with truthiness."""
+  model: Optional[str]
+  main: Optional[str]
+  main_rw: Optional[str]
+  ec: Optional[str]
+  ec_rw: Optional[str]
+
+  def __bool__(self):
+    return bool(
+        self.model or self.main or self.main_rw or self.ec or self.ec_rw)
 
 
-def get_firmware_versions(build_target):
+def get_firmware_versions(build_target: 'build_target_lib.BuildTarget'):
   """Extract version information from the firmware updater, if one exists.
 
   Args:
-    build_target (build_target_lib.BuildTarget): The build target.
+    build_target: The build target.
 
   Returns:
     A FirmwareVersions namedtuple instance.
@@ -1150,11 +1359,12 @@
     return FirmwareVersions(None, None, None, None, None)
 
 
-def _get_firmware_version_cmd_result(build_target):
+def _get_firmware_version_cmd_result(
+    build_target: 'build_target_lib.BuildTarget') -> Optional[str]:
   """Gets the raw result output of the firmware updater version command.
 
   Args:
-    build_target (build_target_lib.BuildTarget): The build target.
+    build_target: The build target.
 
   Returns:
     Command execution result.
@@ -1163,9 +1373,13 @@
                          'usr/sbin/chromeos-firmwareupdate')
   logging.info('Calling updater %s', updater)
   # Call the updater using the chroot-based path.
-  return cros_build_lib.run([updater, '-V'],
-                            capture_output=True, log_output=True,
-                            encoding='utf-8').stdout
+  try:
+    return cros_build_lib.run([updater, '-V'],
+                              capture_output=True, log_output=True,
+                              encoding='utf-8').stdout
+  except cros_build_lib.RunCommandError:
+    # Updater probably doesn't exist (e.g. betty).
+    return None
 
 
 def _find_firmware_versions(cmd_output):
@@ -1215,14 +1429,20 @@
   return FirmwareVersions(model, main, main_rw, ec, ec_rw)
 
 
-MainEcFirmwareVersions = collections.namedtuple(
-    'MainEcFirmwareVersions', ['main_fw_version', 'ec_fw_version'])
+class MainEcFirmwareVersions(NamedTuple):
+  """Tuple to hold main and ec firmware versions, with truthiness."""
+  main_fw_version: Optional[str]
+  ec_fw_version: Optional[str]
 
-def determine_firmware_versions(build_target):
+  def __bool__(self):
+    return bool(self.main_fw_version or self.ec_fw_version)
+
+
+def determine_firmware_versions(build_target: 'build_target_lib.BuildTarget'):
   """Returns a namedtuple with main and ec firmware versions.
 
   Args:
-    build_target (build_target_lib.BuildTarget): The build target.
+    build_target: The build target.
 
   Returns:
     MainEcFirmwareVersions namedtuple with results.
@@ -1233,14 +1453,16 @@
 
   return MainEcFirmwareVersions(main_fw_version, ec_fw_version)
 
-def determine_kernel_version(build_target):
+
+def determine_kernel_version(
+    build_target: 'build_target_lib.BuildTarget') -> Optional[str]:
   """Returns a string containing the kernel version for this build target.
 
   Args:
-    build_target (build_target_lib.BuildTarget): The build target.
+    build_target: The build target.
 
   Returns:
-    (str) The kernel versions, or None.
+    The kernel versions, or None.
   """
   try:
     packages = portage_util.GetPackageDependencies(build_target.name,
@@ -1256,14 +1478,16 @@
   return None
 
 
-def get_models(build_target, log_output=True):
+def get_models(
+    build_target: 'build_target_lib.BuildTarget',
+    log_output: bool = True) -> Optional[List[str]]:
   """Obtain a list of models supported by a unified board.
 
   This ignored whitelabel models since GoldenEye has no specific support for
   these at present.
 
   Args:
-    build_target (build_target_lib.BuildTarget): The build target.
+    build_target: The build target.
     log_output: Whether to log the output of the cros_config_host invocation.
 
   Returns:
@@ -1274,15 +1498,17 @@
                                log_output=log_output)
 
 
-def get_key_id(build_target, model):
+def get_key_id(
+    build_target: 'build_target_lib.BuildTarget',
+    model: str) -> Optional[str]:
   """Obtain the key_id for a model within the build_target.
 
   Args:
-    build_target (build_target_lib.BuildTarget): The build target.
-    model (str): The model name
+    build_target: The build target.
+    model: The model name
 
   Returns:
-    A key_id (str) or None.
+    A key_id or None.
   """
   model_arg = '--model=' + model
   key_id_list = _run_cros_config_host(
@@ -1294,11 +1520,14 @@
   return key_id
 
 
-def _run_cros_config_host(build_target, args, log_output=True):
+def _run_cros_config_host(
+    build_target: 'build_target_lib.BuildTarget',
+    args: List[str],
+    log_output: bool = True) -> Optional[List[str]]:
   """Run the cros_config_host tool.
 
   Args:
-    build_target (build_target_lib.BuildTarget): The build target.
+    build_target: The build target.
     args: List of arguments to pass.
     log_output: Whether to log the output of the cros_config_host.
 
diff --git a/service/packages_unittest.py b/service/packages_unittest.py
index 54b5d36..db98ed5 100644
--- a/service/packages_unittest.py
+++ b/service/packages_unittest.py
@@ -15,9 +15,8 @@
 
 import chromite as cr
 from chromite.api.gen.config.replication_config_pb2 import (
-  ReplicationConfig, FileReplicationRule, FILE_TYPE_JSON,
-  REPLICATION_TYPE_FILTER
-)
+    ReplicationConfig, FileReplicationRule, FILE_TYPE_JSON,
+    REPLICATION_TYPE_FILTER)
 from chromite.cbuildbot import manifest_version
 from chromite.lib import build_target_lib
 from chromite.lib import constants
@@ -32,74 +31,143 @@
 from chromite.lib.chroot_lib import Chroot
 from chromite.lib.parser import package_info
 from chromite.lib.uprev_lib import GitRef
+from chromite.service import android
 from chromite.service import packages
 
-
 D = cros_test_lib.Directory
 
 
 class UprevAndroidTest(cros_test_lib.RunCommandTestCase):
   """Uprev android tests."""
 
+  def _mock_successful_uprev(self):
+    self.rc.AddCmdResult(partial_mock.In('cros_mark_android_as_stable'),
+                         stdout=('{"revved": true,'
+                                 ' "android_atom": "android/android-1.0",'
+                                 ' "modified_files": ["file1", "file2"]}'))
+
   def test_success(self):
     """Test successful run handling."""
-    self.rc.AddCmdResult(partial_mock.In('cros_mark_android_as_stable'),
-                         stdout='ANDROID_ATOM=android/android-1.0\n')
+    self._mock_successful_uprev()
     build_targets = [build_target_lib.BuildTarget(t) for t in ['foo', 'bar']]
 
-    packages.uprev_android('android/package', Chroot(),
-                           build_targets=build_targets)
-    self.assertCommandContains(['cros_mark_android_as_stable',
-                                '--android_package=android/package',
-                                '--boards=foo:bar'])
+    result = packages.uprev_android(
+        'android/package', Chroot(), build_targets=build_targets)
+    self.assertCommandContains([
+        'cros_mark_android_as_stable', '--android_package=android/package',
+        '--boards=foo:bar'
+    ])
     self.assertCommandContains(['emerge-foo'])
     self.assertCommandContains(['emerge-bar'])
 
+    self.assertTrue(result.revved)
+    self.assertEqual(result.android_atom, 'android/android-1.0')
+    self.assertListEqual(result.modified_files, ['file1', 'file2'])
+
   def test_android_build_branch(self):
     """Test specifying android_build_branch option."""
-    self.rc.AddCmdResult(partial_mock.In('cros_mark_android_as_stable'),
-                         stdout='ANDROID_ATOM=android/android-1.0\n')
+    self._mock_successful_uprev()
 
-    packages.uprev_android('android/package', Chroot(),
-                           android_build_branch='android-build-branch')
-    self.assertCommandContains(['cros_mark_android_as_stable',
-                                '--android_package=android/package',
-                                '--android_build_branch=android-build-branch'])
+    packages.uprev_android(
+        'android/package',
+        Chroot(),
+        android_build_branch='android-build-branch')
+    self.assertCommandContains([
+        'cros_mark_android_as_stable', '--android_package=android/package',
+        '--android_build_branch=android-build-branch'
+    ])
 
   def test_android_version(self):
     """Test specifying android_version option."""
-    self.rc.AddCmdResult(partial_mock.In('cros_mark_android_as_stable'),
-                         stdout='ANDROID_ATOM=android/android-1.0\n')
+    self._mock_successful_uprev()
 
-    packages.uprev_android('android/package', Chroot(),
-                           android_version='7123456')
-    self.assertCommandContains(['cros_mark_android_as_stable',
-                                '--android_package=android/package',
-                                '--force_version=7123456'])
+    packages.uprev_android(
+        'android/package', Chroot(), android_version='7123456')
+    self.assertCommandContains([
+        'cros_mark_android_as_stable', '--android_package=android/package',
+        '--force_version=7123456'
+    ])
 
   def test_skip_commit(self):
     """Test specifying skip_commit option."""
-    self.rc.AddCmdResult(partial_mock.In('cros_mark_android_as_stable'),
-                         stdout='ANDROID_ATOM=android/android-1.0\n')
+    self._mock_successful_uprev()
 
     packages.uprev_android('android/package', Chroot(), skip_commit=True)
-    self.assertCommandContains(['cros_mark_android_as_stable',
-                                '--android_package=android/package',
-                                '--skip_commit'])
+    self.assertCommandContains([
+        'cros_mark_android_as_stable', '--android_package=android/package',
+        '--skip_commit'
+    ])
 
   def test_no_uprev(self):
     """Test no uprev handling."""
     self.rc.AddCmdResult(partial_mock.In('cros_mark_android_as_stable'),
-                         stdout='')
+                         stdout='{"revved": false}')
     build_targets = [build_target_lib.BuildTarget(t) for t in ['foo', 'bar']]
-    packages.uprev_android('android/package', Chroot(),
-                           build_targets=build_targets)
+    result = packages.uprev_android(
+        'android/package', Chroot(), build_targets=build_targets)
 
-    self.assertCommandContains(['cros_mark_android_as_stable',
-                                '--boards=foo:bar'])
+    self.assertCommandContains(
+        ['cros_mark_android_as_stable', '--boards=foo:bar'])
     self.assertCommandContains(['emerge-foo'], expected=False)
     self.assertCommandContains(['emerge-bar'], expected=False)
 
+    self.assertFalse(result.revved)
+
+  def test_ignore_junk_in_stdout(self):
+    """Test when stdout contains junk messages."""
+    self.rc.AddCmdResult(partial_mock.In('cros_mark_android_as_stable'),
+                         stdout='foo\nbar\n{"revved": false}\n')
+    result = packages.uprev_android('android/package', Chroot())
+
+    self.assertFalse(result.revved)
+
+
+class UprevAndroidLKGBTest(cros_test_lib.MockTestCase):
+  """Tests for uprevving Android with LKGB."""
+
+  def test_registered_handlers(self):
+    """Test that each Android package has an uprev handler registered."""
+    mock_handler = self.PatchObject(packages, 'uprev_android_lkgb')
+
+    for android_package in constants.ANDROID_ALL_PACKAGES:
+      cpv = package_info.SplitCPV('chromeos-base/' + android_package,
+                                  strict=False)
+      build_targets = [build_target_lib.BuildTarget('foo')]
+      chroot = Chroot()
+
+      packages.uprev_versioned_package(cpv, build_targets, [], chroot)
+
+      mock_handler.assert_called_once_with(android_package, build_targets,
+                                           chroot)
+      mock_handler.reset_mock()
+
+  def test_success(self):
+    """Test a successful uprev."""
+    self.PatchObject(android, 'OVERLAY_DIR', new='overlay-dir')
+    self.PatchObject(android, 'ReadLKGB', return_value='android-lkgb')
+    self.PatchObject(packages, 'uprev_android',
+                     return_value=packages.UprevAndroidResult(
+                         revved=True, android_atom='android-atom',
+                         modified_files=['file1', 'file2']))
+
+    result = packages.uprev_android_lkgb('android-package', [], Chroot())
+
+    self.assertListEqual(result.modified,
+                         [uprev_lib.UprevVersionedPackageModifications(
+                             'android-lkgb',
+                             [os.path.join('overlay-dir', 'file1'),
+                              os.path.join('overlay-dir', 'file2')])])
+
+  def test_no_rev(self):
+    """Test when nothing revved."""
+    self.PatchObject(android, 'ReadLKGB', return_value='android-lkgb')
+    self.PatchObject(packages, 'uprev_android',
+                     return_value=packages.UprevAndroidResult(revved=False))
+
+    result = packages.uprev_android_lkgb('android-package', [], Chroot())
+
+    self.assertListEqual(result.modified, [])
+
 
 class UprevBuildTargetsTest(cros_test_lib.RunCommandTestCase):
   """uprev_build_targets tests."""
@@ -113,8 +181,7 @@
   def test_none_type_fails(self):
     """Test None type fails."""
     with self.assertRaises(AssertionError):
-      packages.uprev_build_targets([build_target_lib.BuildTarget('foo')],
-                                   None)
+      packages.uprev_build_targets([build_target_lib.BuildTarget('foo')], None)
 
 
 class UprevsVersionedPackageTest(cros_test_lib.MockTestCase):
@@ -155,10 +222,8 @@
 
   def test_uprev_ebuild(self):
     """Tests uprev of ebuild with version path"""
-    file_layout = (
-        D(self.package, [self.ebuild, self.unstable_ebuild,
-                         self.manifest]),
-    )
+    file_layout = (D(self.package,
+                     [self.ebuild, self.unstable_ebuild, self.manifest]),)
     cros_test_lib.CreateOnDiskHierarchy(self.tempdir, file_layout)
 
     package_path = os.path.join(self.tempdir, self.package)
@@ -168,8 +233,9 @@
 
     result = uprev_lib.uprev_ebuild_from_pin(
         package_path, self.new_version, chroot=Chroot())
-    self.assertEqual(len(result.modified), 1,
-                     'unexpected number of results: %s' % len(result.modified))
+    self.assertEqual(
+        len(result.modified), 1,
+        'unexpected number of results: %s' % len(result.modified))
 
     mod = result.modified[0]
     self.assertEqual(mod.new_version, self.new_version + '-r1',
@@ -191,10 +257,8 @@
 
        This should result in bumping the revision number.
     """
-    file_layout = (
-        D(self.package, [self.ebuild, self.unstable_ebuild,
-                         self.manifest]),
-    )
+    file_layout = (D(self.package,
+                     [self.ebuild, self.unstable_ebuild, self.manifest]),)
     cros_test_lib.CreateOnDiskHierarchy(self.tempdir, file_layout)
 
     package_path = os.path.join(self.tempdir, self.package)
@@ -204,8 +268,9 @@
 
     result = uprev_lib.uprev_ebuild_from_pin(
         package_path, self.version, chroot=Chroot())
-    self.assertEqual(len(result.modified), 1,
-                     'unexpected number of results: %s' % len(result.modified))
+    self.assertEqual(
+        len(result.modified), 1,
+        'unexpected number of results: %s' % len(result.modified))
 
     mod = result.modified[0]
     self.assertEqual(mod.new_version, self.version + '-r2',
@@ -224,9 +289,7 @@
 
   def test_no_ebuild(self):
     """Tests assertion is raised if package has no ebuilds"""
-    file_layout = (
-        D(self.package, [self.manifest]),
-    )
+    file_layout = (D(self.package, [self.manifest]),)
     cros_test_lib.CreateOnDiskHierarchy(self.tempdir, file_layout)
 
     package_path = os.path.join(self.tempdir, self.package)
@@ -237,11 +300,9 @@
 
   def test_multiple_stable_ebuilds(self):
     """Tests assertion is raised if multiple stable ebuilds are present"""
-    file_layout = (
-        D(self.package, [self.ebuild,
-                         self.ebuild_template % '1.2.1',
-                         self.manifest]),
-    )
+    file_layout = (D(
+        self.package,
+        [self.ebuild, self.ebuild_template % '1.2.1', self.manifest]),)
     cros_test_lib.CreateOnDiskHierarchy(self.tempdir, file_layout)
 
     package_path = os.path.join(self.tempdir, self.package)
@@ -258,11 +319,9 @@
 
   def test_multiple_unstable_ebuilds(self):
     """Tests assertion is raised if multiple unstable ebuilds are present"""
-    file_layout = (
-        D(self.package, [self.ebuild,
-                         self.ebuild_template % '1.2.1',
-                         self.manifest]),
-    )
+    file_layout = (D(
+        self.package,
+        [self.ebuild, self.ebuild_template % '1.2.1', self.manifest]),)
     cros_test_lib.CreateOnDiskHierarchy(self.tempdir, file_layout)
 
     package_path = os.path.join(self.tempdir, self.package)
@@ -279,8 +338,7 @@
     # Set up fake public and private chromeos-config overlays.
     private_package_root = (
         'src/private-overlays/overlay-coral-private/chromeos-base/'
-        'chromeos-config-bsp'
-    )
+        'chromeos-config-bsp')
     self.public_package_root = (
         'src/overlays/overlay-coral/chromeos-base/chromeos-config-bsp')
     file_layout = (
@@ -515,12 +573,7 @@
   def test_replicate_private_config_wrong_git_ref_path(self):
     """An error is thrown if the git ref doesn't point to a private overlay."""
     with self.assertRaisesRegex(ValueError, 'ref.path must match the pattern'):
-      refs = [
-          GitRef(
-              path='a/b/c',
-              ref='main',
-              revision='123')
-      ]
+      refs = [GitRef(path='a/b/c', ref='main', revision='123')]
       packages.replicate_private_config(
           _build_targets=None, refs=refs, chroot=None)
 
@@ -550,8 +603,8 @@
     self.PatchObject(os.environ, 'get', return_value='')
 
     packages.has_prebuilt('cat/pkg-1.2.3', useflags='useflag')
-    patch.assert_called_with('cat/pkg-1.2.3', board=None,
-                             extra_env={'USE': 'useflag'})
+    patch.assert_called_with(
+        'cat/pkg-1.2.3', board=None, extra_env={'USE': 'useflag'})
 
   def test_env_use_flags(self):
     """Test env use flags get propagated correctly with passed useflags."""
@@ -564,9 +617,8 @@
     new_flags = 'useflag'
     packages.has_prebuilt('cat/pkg-1.2.3', useflags=new_flags)
     expected = '%s %s' % (existing_flags, new_flags)
-    patch.assert_called_with('cat/pkg-1.2.3', board=None,
-                             extra_env={'USE': expected})
-
+    patch.assert_called_with(
+        'cat/pkg-1.2.3', board=None, extra_env={'USE': expected})
 
 
 class AndroidVersionsTest(cros_test_lib.MockTestCase):
@@ -575,17 +627,24 @@
   def setUp(self):
     package_result = [
         'chromeos-base/android-container-nyc-4717008-r1',
-        'chromeos-base/update_engine-0.0.3-r3408']
-    self.PatchObject(portage_util, 'GetPackageDependencies',
-                     return_value=package_result)
+        'chromeos-base/update_engine-0.0.3-r3408'
+    ]
+    self.PatchObject(
+        portage_util, 'GetPackageDependencies', return_value=package_result)
     self.board = 'board'
-    self.PatchObject(portage_util, 'FindEbuildForBoardPackage',
-                     return_value='chromeos-base/android-container-nyc')
+    self.PatchObject(
+        portage_util,
+        'FindEbuildForBoardPackage',
+        return_value='chromeos-base/android-container-nyc')
     FakeEnvironment = {
         'ARM_TARGET': '3-linux-target',
     }
-    self.PatchObject(osutils, 'SourceEnvironment',
-                     return_value=FakeEnvironment)
+    self.PatchObject(osutils, 'SourceEnvironment', return_value=FakeEnvironment)
+
+    # Clear the LRU cache for the function. We mock the function that provides
+    # the data this function processes to produce its result, so we need to
+    # clear it manually.
+    packages.determine_android_package.cache_clear()
 
   def test_determine_android_version(self):
     """Tests that a valid android version is returned."""
@@ -595,8 +654,8 @@
   def test_determine_android_version_when_not_present(self):
     """Tests that a None is returned for version when android is not present."""
     package_result = ['chromeos-base/update_engine-0.0.3-r3408']
-    self.PatchObject(portage_util, 'GetPackageDependencies',
-                     return_value=package_result)
+    self.PatchObject(
+        portage_util, 'GetPackageDependencies', return_value=package_result)
     version = packages.determine_android_version(self.board)
     self.assertEqual(version, None)
 
@@ -607,16 +666,18 @@
 
   def test_determine_android_branch_64bit_targets(self):
     """Tests that a valid android branch is returned with only 64bit targets."""
-    self.PatchObject(osutils, 'SourceEnvironment',
-                     return_value={'ARM64_TARGET': '3-linux-target'})
+    self.PatchObject(
+        osutils,
+        'SourceEnvironment',
+        return_value={'ARM64_TARGET': '3-linux-target'})
     branch = packages.determine_android_branch(self.board)
     self.assertEqual(branch, '3')
 
   def test_determine_android_branch_when_not_present(self):
     """Tests that a None is returned for branch when android is not present."""
     package_result = ['chromeos-base/update_engine-0.0.3-r3408']
-    self.PatchObject(portage_util, 'GetPackageDependencies',
-                     return_value=package_result)
+    self.PatchObject(
+        portage_util, 'GetPackageDependencies', return_value=package_result)
     branch = packages.determine_android_branch(self.board)
     self.assertEqual(branch, None)
 
@@ -628,8 +689,8 @@
   def test_determine_android_target_when_not_present(self):
     """Tests that a None is returned for target when android is not present."""
     package_result = ['chromeos-base/update_engine-0.0.3-r3408']
-    self.PatchObject(portage_util, 'GetPackageDependencies',
-                     return_value=package_result)
+    self.PatchObject(
+        portage_util, 'GetPackageDependencies', return_value=package_result)
     target = packages.determine_android_target(self.board)
     self.assertEqual(target, None)
 
@@ -637,8 +698,10 @@
     """Tests handling RunCommandError inside determine_android_version."""
     # Mock what happens when portage returns that bubbles up (via RunCommand)
     # inside portage_util.GetPackageDependencies.
-    self.PatchObject(portage_util, 'GetPackageDependencies',
-                     side_effect=cros_build_lib.RunCommandError('error'))
+    self.PatchObject(
+        portage_util,
+        'GetPackageDependencies',
+        side_effect=cros_build_lib.RunCommandError('error'))
     target = packages.determine_android_version(self.board)
     self.assertEqual(target, None)
 
@@ -646,8 +709,10 @@
     """Tests handling RunCommandError inside determine_android_package."""
     # Mock what happens when portage returns that bubbles up (via RunCommand)
     # inside portage_util.GetPackageDependencies.
-    self.PatchObject(portage_util, 'GetPackageDependencies',
-                     side_effect=cros_build_lib.RunCommandError('error'))
+    self.PatchObject(
+        portage_util,
+        'GetPackageDependencies',
+        side_effect=cros_build_lib.RunCommandError('error'))
     target = packages.determine_android_package(self.board)
     self.assertEqual(target, None)
 
@@ -655,8 +720,10 @@
     """Tests handling RunCommandError by determine_android_package callers."""
     # Mock what happens when portage returns that bubbles up (via RunCommand)
     # inside portage_util.GetPackageDependencies.
-    self.PatchObject(portage_util, 'GetPackageDependencies',
-                     side_effect=cros_build_lib.RunCommandError('error'))
+    self.PatchObject(
+        portage_util,
+        'GetPackageDependencies',
+        side_effect=cros_build_lib.RunCommandError('error'))
     # Verify that target is None, as expected.
     target = packages.determine_android_package(self.board)
     self.assertEqual(target, None)
@@ -675,15 +742,14 @@
   def setUp(self):
     self.board = 'test-board'
     # Create cheets-fingerprints.txt based on tempdir/src...
-    self.fingerprint_contents = (
-        'google/test-board/test-board_cheets'
-        ':9/R99-12345.0.9999/123456:user/release-keys')
+    self.fingerprint_contents = ('google/test-board/test-board_cheets'
+                                 ':9/R99-12345.0.9999/123456:user/release-keys')
     fingerprint_path = os.path.join(
         self.tempdir,
         'src/build/images/test-board/latest/cheets-fingerprint.txt')
     self.chroot = Chroot(self.tempdir)
-    osutils.WriteFile(fingerprint_path, self.fingerprint_contents,
-                      makedirs=True)
+    osutils.WriteFile(
+        fingerprint_path, self.fingerprint_contents, makedirs=True)
 
   def test_find_fingerprints_with_test_path(self):
     """Tests get_firmware_versions with mocked output."""
@@ -787,44 +853,41 @@
     self.assertEqual(len(result), 5)
     self.assertEqual(
         result['reef'],
-        packages.FirmwareVersions(
-            'reef',
-            'Google_Reef.9042.87.1',
-            'Google_Reef.9042.110.0',
-            'reef_v1.1.5900-ab1ee51',
-            'reef_v1.1.5909-bd1f0c9'))
+        packages.FirmwareVersions('reef', 'Google_Reef.9042.87.1',
+                                  'Google_Reef.9042.110.0',
+                                  'reef_v1.1.5900-ab1ee51',
+                                  'reef_v1.1.5909-bd1f0c9'))
     self.assertEqual(
         result['pyro'],
-        packages.FirmwareVersions(
-            'pyro',
-            'Google_Pyro.9042.87.1',
-            'Google_Pyro.9042.110.0',
-            'pyro_v1.1.5900-ab1ee51',
-            'pyro_v1.1.5909-bd1f0c9'))
+        packages.FirmwareVersions('pyro', 'Google_Pyro.9042.87.1',
+                                  'Google_Pyro.9042.110.0',
+                                  'pyro_v1.1.5900-ab1ee51',
+                                  'pyro_v1.1.5909-bd1f0c9'))
     self.assertEqual(
         result['snappy'],
-        packages.FirmwareVersions(
-            'snappy',
-            'Google_Snappy.9042.110.0',
-            None,
-            'snappy_v1.1.5909-bd1f0c9',
-            None))
+        packages.FirmwareVersions('snappy', 'Google_Snappy.9042.110.0', None,
+                                  'snappy_v1.1.5909-bd1f0c9', None))
     self.assertEqual(
         result['sand'],
-        packages.FirmwareVersions(
-            'sand',
-            'Google_Sand.9042.110.0',
-            None,
-            'sand_v1.1.5909-bd1f0c9',
-            None))
+        packages.FirmwareVersions('sand', 'Google_Sand.9042.110.0', None,
+                                  'sand_v1.1.5909-bd1f0c9', None))
     self.assertEqual(
         result['electro'],
-        packages.FirmwareVersions(
-            'electro',
-            'Google_Reef.9042.87.1',
-            'Google_Reef.9042.110.0',
-            'reef_v1.1.5900-ab1ee51',
-            'reef_v1.1.5909-bd1f0c9'))
+        packages.FirmwareVersions('electro', 'Google_Reef.9042.87.1',
+                                  'Google_Reef.9042.110.0',
+                                  'reef_v1.1.5900-ab1ee51',
+                                  'reef_v1.1.5909-bd1f0c9'))
+
+  def test_get_firmware_versions_error(self):
+    """Tests get_firmware_versions with no output."""
+    # Throw an exception when running the command.
+    self.PatchObject(
+        cros_build_lib,
+        'run',
+        side_effect=cros_build_lib.RunCommandError('error'))
+    build_target = build_target_lib.BuildTarget(self.board)
+    result = packages.get_all_firmware_versions(build_target)
+    self.assertEqual(result, {})
 
 
 class GetFirmwareVersionsTest(cros_test_lib.RunCommandTempDirTestCase):
@@ -863,8 +926,8 @@
     """Tests get_firmware_versions with mocked output."""
     build_target = build_target_lib.BuildTarget(self.board)
     result = packages.get_firmware_versions(build_target)
-    versions = packages.FirmwareVersions(
-        None, 'Google_Kevin.8785.178.0', None, 'kevin_v1.10.184-459421c', None)
+    versions = packages.FirmwareVersions(None, 'Google_Kevin.8785.178.0', None,
+                                         'kevin_v1.10.184-459421c', None)
     self.assertEqual(result, versions)
 
 
@@ -877,22 +940,26 @@
 
   def test_determine_kernel_version(self):
     """Tests that a valid kernel version is returned."""
-    package_result = ['sys-kernel/linux-headers-4.14-r24',
-                      'sys-devel/flex-2.6.4-r1',
-                      'sys-kernel/chromeos-kernel-4_4-4.4.223-r2209']
-    self.PatchObject(portage_util, 'GetPackageDependencies',
-                     return_value=package_result)
+    package_result = [
+        'sys-kernel/linux-headers-4.14-r24', 'sys-devel/flex-2.6.4-r1',
+        'sys-kernel/chromeos-kernel-4_4-4.4.223-r2209'
+    ]
+    self.PatchObject(
+        portage_util, 'GetPackageDependencies', return_value=package_result)
 
     result = packages.determine_kernel_version(self.build_target)
     self.assertEqual(result, '4.4.223-r2209')
 
   def test_determine_kernel_version_exception(self):
     """Tests that portage_util exceptions result in returning None."""
-    self.PatchObject(portage_util, 'GetPackageDependencies',
-                     side_effect=cros_build_lib.RunCommandError('error'))
+    self.PatchObject(
+        portage_util,
+        'GetPackageDependencies',
+        side_effect=cros_build_lib.RunCommandError('error'))
     result = packages.determine_kernel_version(self.build_target)
     self.assertEqual(result, None)
 
+
 class ChromeVersionsTest(cros_test_lib.MockTestCase):
   """Tests getting chrome version."""
 
@@ -904,8 +971,7 @@
     # Mock PortageqBestVisible to return a valid chrome version string.
     r1_cpf = 'chromeos-base/chromeos-chrome-78.0.3900.0_rc-r1'
     r1_cpv = package_info.SplitCPV(r1_cpf)
-    self.PatchObject(portage_util, 'PortageqBestVisible',
-                     return_value=r1_cpv)
+    self.PatchObject(portage_util, 'PortageqBestVisible', return_value=r1_cpv)
 
     chrome_version = packages.determine_chrome_version(self.build_target)
     version_numbers = chrome_version.split('.')
@@ -915,8 +981,10 @@
   def test_determine_chrome_version_handle_exception(self):
     # Mock what happens when portage throws an exception that bubbles up (via
     # RunCommand)inside portage_util.PortageqBestVisible.
-    self.PatchObject(portage_util, 'PortageqBestVisible',
-                     side_effect=cros_build_lib.RunCommandError('error'))
+    self.PatchObject(
+        portage_util,
+        'PortageqBestVisible',
+        side_effect=cros_build_lib.RunCommandError('error'))
     target = packages.determine_chrome_version(self.build_target)
     self.assertEqual(target, None)
 
@@ -956,8 +1024,10 @@
     test_chrome_branch = '75'
     version_info_mock = manifest_version.VersionInfo(test_platform_version)
     version_info_mock.chrome_branch = test_chrome_branch
-    self.PatchObject(manifest_version.VersionInfo, 'from_repo',
-                     return_value=version_info_mock)
+    self.PatchObject(
+        manifest_version.VersionInfo,
+        'from_repo',
+        return_value=version_info_mock)
     test_full_version = 'R' + test_chrome_branch + '-' + test_platform_version
     platform_version = packages.determine_platform_version()
     milestone_version = packages.determine_milestone_version()
@@ -1057,8 +1127,7 @@
       GitRef(
           path='/foo', ref=f'refs/tags/{new_version}', revision='dummycommit')
   ]
-  res = packages.uprev_chrome_from_ref(build_targets=None, refs=git_refs,
-                                       chroot=None)
+  res = packages.uprev_chrome_from_ref(None, git_refs, None)
 
   modified_file_count = sum(len(m.files) for m in res.modified)
   assert modified_file_count == expected_count
@@ -1072,8 +1141,8 @@
     self.board = 'test-board'
     self.rc.SetDefaultCmdResult(output='pyro\nreef\nsnappy\n')
     self.monkeypatch.setattr(constants, 'SOURCE_ROOT', self.tempdir)
-    build_bin = os.path.join(self.tempdir, constants.DEFAULT_CHROOT_DIR,
-                             'usr', 'bin')
+    build_bin = os.path.join(self.tempdir, constants.DEFAULT_CHROOT_DIR, 'usr',
+                             'bin')
     osutils.Touch(os.path.join(build_bin, 'cros_config_host'), makedirs=True)
 
   def testGetModels(self):
@@ -1092,15 +1161,14 @@
 
   def testGetKeyId(self):
     """Test get_key_id when _run_cros_config_host returns a key."""
-    self.PatchObject(packages, '_run_cros_config_host',
-                     return_value=['key'])
+    self.PatchObject(packages, '_run_cros_config_host', return_value=['key'])
     result = packages.get_key_id(self.build_target, 'model')
     self.assertEqual(result, 'key')
 
   def testGetKeyIdNoKey(self):
     """Test get_key_id when None should be returned."""
-    self.PatchObject(packages, '_run_cros_config_host',
-                     return_value=['key1', 'key2'])
+    self.PatchObject(
+        packages, '_run_cros_config_host', return_value=['key1', 'key2'])
     result = packages.get_key_id(self.build_target, 'model')
     self.assertEqual(result, None)
 
@@ -1116,26 +1184,29 @@
     self.latest = '44.0.20'
     self.versions = ['42.0.1', self.latest, '44.0.19', '39.0.15']
     self.latest_ref = uprev_lib.GitRef('/path', ref_tpl % self.latest, 'abc123')
-    self.refs = [uprev_lib.GitRef('/path', ref_tpl % v, 'abc123')
-                 for v in self.versions]
+    self.refs = [
+        uprev_lib.GitRef('/path', ref_tpl % v, 'abc123') for v in self.versions
+    ]
 
   def test_single_ref(self):
     """Test a single ref is supplied."""
     # pylint: disable=protected-access
-    self.assertEqual(self.latest,
+    self.assertEqual(
+        self.latest,
         packages._get_latest_version_from_refs(self.prefix, [self.latest_ref]))
 
   def test_multiple_ref_versions(self):
     """Test multiple refs supplied."""
     # pylint: disable=protected-access
-    self.assertEqual(self.latest,
+    self.assertEqual(
+        self.latest,
         packages._get_latest_version_from_refs(self.prefix, self.refs))
 
   def test_no_refs_returns_none(self):
     """Test no refs supplied."""
     # pylint: disable=protected-access
-    self.assertEqual(packages._get_latest_version_from_refs(self.prefix, []),
-                     None)
+    self.assertEqual(
+        packages._get_latest_version_from_refs(self.prefix, []), None)
 
 
 class NeedsChromeSourceTest(cros_test_lib.MockTestCase):
@@ -1163,8 +1234,8 @@
   def test_needs_all(self):
     """Verify we need source when we have no prebuilts."""
     graph = self._build_graph(with_chrome=True, with_followers=True)
-    self.PatchObject(depgraph, 'get_sysroot_dependency_graph',
-                     return_value=graph)
+    self.PatchObject(
+        depgraph, 'get_sysroot_dependency_graph', return_value=graph)
     self.PatchObject(packages, 'has_prebuilt', return_value=False)
     self.PatchObject(
         packages,
@@ -1178,8 +1249,9 @@
     self.assertTrue(result.needs_chrome_source)
     self.assertTrue(result.builds_chrome)
     self.assertTrue(result.packages)
-    self.assertEqual(len(result.packages),
-                     len(constants.OTHER_CHROME_PACKAGES) + 1)
+    self.assertEqual(
+        len(result.packages),
+        len(constants.OTHER_CHROME_PACKAGES) + 1)
     self.assertTrue(result.missing_chrome_prebuilt)
     self.assertTrue(result.missing_follower_prebuilt)
     self.assertFalse(result.local_uprev)
@@ -1187,8 +1259,8 @@
   def test_needs_none(self):
     """Verify not building any of the chrome packages prevents needing it."""
     graph = self._build_graph(with_chrome=False, with_followers=False)
-    self.PatchObject(depgraph, 'get_sysroot_dependency_graph',
-                     return_value=graph)
+    self.PatchObject(
+        depgraph, 'get_sysroot_dependency_graph', return_value=graph)
     self.PatchObject(packages, 'has_prebuilt', return_value=False)
     self.PatchObject(
         packages,
@@ -1209,8 +1281,8 @@
   def test_needs_chrome_only(self):
     """Verify only chrome triggers needs chrome source."""
     graph = self._build_graph(with_chrome=True, with_followers=False)
-    self.PatchObject(depgraph, 'get_sysroot_dependency_graph',
-                     return_value=graph)
+    self.PatchObject(
+        depgraph, 'get_sysroot_dependency_graph', return_value=graph)
     self.PatchObject(packages, 'has_prebuilt', return_value=False)
     self.PatchObject(
         packages,
@@ -1224,8 +1296,8 @@
     self.assertTrue(result.needs_chrome_source)
     self.assertTrue(result.builds_chrome)
     self.assertTrue(result.packages)
-    self.assertEqual(set([p.atom for p in result.packages]),
-                     {constants.CHROME_CP})
+    self.assertEqual(
+        set([p.atom for p in result.packages]), {constants.CHROME_CP})
     self.assertTrue(result.missing_chrome_prebuilt)
     self.assertFalse(result.missing_follower_prebuilt)
     self.assertFalse(result.local_uprev)
@@ -1233,8 +1305,8 @@
   def test_needs_followers_only(self):
     """Verify only chrome followers triggers needs chrome source."""
     graph = self._build_graph(with_chrome=False, with_followers=True)
-    self.PatchObject(depgraph, 'get_sysroot_dependency_graph',
-                     return_value=graph)
+    self.PatchObject(
+        depgraph, 'get_sysroot_dependency_graph', return_value=graph)
     self.PatchObject(packages, 'has_prebuilt', return_value=False)
     self.PatchObject(
         packages,
@@ -1248,8 +1320,9 @@
     self.assertTrue(result.needs_chrome_source)
     self.assertFalse(result.builds_chrome)
     self.assertTrue(result.packages)
-    self.assertEqual(set([p.atom for p in result.packages]),
-                     set(constants.OTHER_CHROME_PACKAGES))
+    self.assertEqual(
+        set([p.atom for p in result.packages]),
+        set(constants.OTHER_CHROME_PACKAGES))
     self.assertFalse(result.missing_chrome_prebuilt)
     self.assertTrue(result.missing_follower_prebuilt)
     self.assertFalse(result.local_uprev)
@@ -1257,8 +1330,8 @@
   def test_has_prebuilts(self):
     """Test prebuilts prevent us from needing chrome source."""
     graph = self._build_graph(with_chrome=True, with_followers=True)
-    self.PatchObject(depgraph, 'get_sysroot_dependency_graph',
-                     return_value=graph)
+    self.PatchObject(
+        depgraph, 'get_sysroot_dependency_graph', return_value=graph)
     self.PatchObject(packages, 'has_prebuilt', return_value=True)
     self.PatchObject(
         packages,
@@ -1279,8 +1352,8 @@
   def test_compile_source(self):
     """Test compile source ignores prebuilts."""
     graph = self._build_graph(with_chrome=True, with_followers=True)
-    self.PatchObject(depgraph, 'get_sysroot_dependency_graph',
-                     return_value=graph)
+    self.PatchObject(
+        depgraph, 'get_sysroot_dependency_graph', return_value=graph)
     self.PatchObject(packages, 'has_prebuilt', return_value=True)
     self.PatchObject(
         packages,
@@ -1294,8 +1367,9 @@
     self.assertTrue(result.needs_chrome_source)
     self.assertTrue(result.builds_chrome)
     self.assertTrue(result.packages)
-    self.assertEqual(len(result.packages),
-                     len(constants.OTHER_CHROME_PACKAGES) + 1)
+    self.assertEqual(
+        len(result.packages),
+        len(constants.OTHER_CHROME_PACKAGES) + 1)
     self.assertTrue(result.missing_chrome_prebuilt)
     self.assertTrue(result.missing_follower_prebuilt)
     self.assertFalse(result.local_uprev)
@@ -1303,8 +1377,8 @@
   def test_local_uprev(self):
     """Test compile source ignores prebuilts."""
     graph = self._build_graph(with_chrome=True, with_followers=True)
-    self.PatchObject(depgraph, 'get_sysroot_dependency_graph',
-                     return_value=graph)
+    self.PatchObject(
+        depgraph, 'get_sysroot_dependency_graph', return_value=graph)
     self.PatchObject(packages, 'has_prebuilt', return_value=False)
 
     uprev_result = uprev_lib.UprevVersionedPackageResult()
@@ -1318,8 +1392,9 @@
     self.assertTrue(result.needs_chrome_source)
     self.assertTrue(result.builds_chrome)
     self.assertTrue(result.packages)
-    self.assertEqual(len(result.packages),
-                     len(constants.OTHER_CHROME_PACKAGES) + 1)
+    self.assertEqual(
+        len(result.packages),
+        len(constants.OTHER_CHROME_PACKAGES) + 1)
     self.assertTrue(result.missing_chrome_prebuilt)
     self.assertTrue(result.missing_follower_prebuilt)
     self.assertTrue(result.local_uprev)
@@ -1336,7 +1411,6 @@
             revision='123')
     ]
     self.MOCK_DRIVEFS_EBUILD_PATH = 'drivefs.45.0.2-r1.ebuild'
-    self.MOCK_DRIVEFS_IPC_EBUILD_PATH = 'drivefs-ipc.45.0.2-r1.ebuild'
 
   def revisionBumpOutcome(self, ebuild_path):
     return uprev_lib.UprevResult(uprev_lib.Outcome.REVISION_BUMP, [ebuild_path])
@@ -1362,55 +1436,30 @@
   def test_same_version_exists(self):
     """Test the same version exists uprev should not happen."""
     drivefs_outcome = self.sameVersionOutcome()
-    drivefs_ipc_outcome = self.sameVersionOutcome()
     self.PatchObject(
         uprev_lib,
         'uprev_workon_ebuild_to_version',
-        side_effect=[drivefs_outcome, drivefs_ipc_outcome])
-    output = packages.uprev_drivefs(None, self.refs, None)
-    self.assertFalse(output.uprevved)
-
-  def test_revision_bump_just_drivefs_package(self):
-    """Test drivefs package uprevs not drivefs-ipc, should not uprev."""
-    drivefs_outcome = self.revisionBumpOutcome(self.MOCK_DRIVEFS_EBUILD_PATH)
-    self.PatchObject(
-        uprev_lib,
-        'uprev_workon_ebuild_to_version',
-        side_effect=[drivefs_outcome, None])
+        side_effect=[drivefs_outcome])
     output = packages.uprev_drivefs(None, self.refs, None)
     self.assertFalse(output.uprevved)
 
   def test_revision_bump_both_packages(self):
     """Test both packages uprev, should succeed."""
     drivefs_outcome = self.revisionBumpOutcome(self.MOCK_DRIVEFS_EBUILD_PATH)
-    drivefs_ipc_outcome = self.revisionBumpOutcome(
-        self.MOCK_DRIVEFS_IPC_EBUILD_PATH)
     self.PatchObject(
         uprev_lib,
         'uprev_workon_ebuild_to_version',
-        side_effect=[drivefs_outcome, drivefs_ipc_outcome])
+        side_effect=[drivefs_outcome])
     output = packages.uprev_drivefs(None, self.refs, None)
     self.assertTrue(output.uprevved)
 
-  def test_major_bump_only_drivefs_packages(self):
-    """Test drivefs package uprevs not drivefs-ipc, should not uprev."""
-    drivefs_outcome = self.majorBumpOutcome(self.MOCK_DRIVEFS_EBUILD_PATH)
-    self.PatchObject(
-        uprev_lib,
-        'uprev_workon_ebuild_to_version',
-        side_effect=[drivefs_outcome, None])
-    output = packages.uprev_drivefs(None, self.refs, None)
-    self.assertFalse(output.uprevved)
-
   def test_major_bump_both_packages(self):
     """Test both packages uprev, should succeed."""
     drivefs_outcome = self.majorBumpOutcome(self.MOCK_DRIVEFS_EBUILD_PATH)
-    drivefs_ipc_outcome = self.majorBumpOutcome(
-        self.MOCK_DRIVEFS_IPC_EBUILD_PATH)
     self.PatchObject(
         uprev_lib,
         'uprev_workon_ebuild_to_version',
-        side_effect=[drivefs_outcome, drivefs_ipc_outcome])
+        side_effect=[drivefs_outcome])
     output = packages.uprev_drivefs(None, self.refs, None)
     self.assertTrue(output.uprevved)
 
@@ -1420,12 +1469,7 @@
   """Tests for uprev_perfetto."""
 
   def setUp(self):
-    self.refs = [
-        GitRef(
-            path='/foo',
-            ref='refs/tags/v12.0',
-            revision='123')
-    ]
+    self.refs = [GitRef(path='/foo', ref='refs/tags/v12.0', revision='123')]
     self.MOCK_PERFETTO_EBUILD_PATH = 'perfetto-12.0-r1.ebuild'
 
   def revisionBumpOutcome(self, ebuild_path):
@@ -1492,16 +1536,13 @@
     output = packages.uprev_perfetto(None, self.refs, None)
     self.assertTrue(output.uprevved)
 
+
 class UprevLacrosTest(cros_test_lib.MockTestCase):
   """Tests for uprev_lacros"""
 
   def setUp(self):
     self.refs = [
-      GitRef(
-        path='/lacros',
-        ref='refs/heads/main',
-        revision='123.456.789.0'
-      )
+        GitRef(path='/lacros', ref='refs/heads/main', revision='123.456.789.0')
     ]
     self.MOCK_LACROS_EBUILD_PATH = 'chromeos-lacros-123.456.789.0-r1.ebuild'
 
@@ -1512,72 +1553,155 @@
     return uprev_lib.UprevResult(uprev_lib.Outcome.VERSION_BUMP, [ebuild_path])
 
   def newerVersionOutcome(self, ebuild_path):
-    return uprev_lib.UprevResult(
-        uprev_lib.Outcome.NEWER_VERSION_EXISTS, [ebuild_path])
+    return uprev_lib.UprevResult(uprev_lib.Outcome.NEWER_VERSION_EXISTS,
+                                 [ebuild_path])
 
   def sameVersionOutcome(self, ebuild_path):
-    return uprev_lib.UprevResult(
-        uprev_lib.Outcome.SAME_VERSION_EXISTS, [ebuild_path])
+    return uprev_lib.UprevResult(uprev_lib.Outcome.SAME_VERSION_EXISTS,
+                                 [ebuild_path])
 
   def newEbuildCreatedOutcome(self, ebuild_path):
-    return uprev_lib.UprevResult(
-        uprev_lib.Outcome.NEW_EBUILD_CREATED, [ebuild_path])
+    return uprev_lib.UprevResult(uprev_lib.Outcome.NEW_EBUILD_CREATED,
+                                 [ebuild_path])
 
   def test_lacros_uprev_fails(self):
+    """Test a lacros package uprev with no triggers"""
     self.PatchObject(
-      uprev_lib,
-      'uprev_workon_ebuild_to_version',
-      side_effect=[None]
-    )
+        uprev_lib, 'uprev_workon_ebuild_to_version', side_effect=[None])
     with self.assertRaises(IndexError):
       packages.uprev_lacros(None, [], None)
 
   def test_lacros_uprev_revision_bump(self):
+    """Test lacros package uprev."""
     lacros_outcome = self.revisionBumpOutcome(self.MOCK_LACROS_EBUILD_PATH)
     self.PatchObject(
-      uprev_lib,
-      'uprev_workon_ebuild_to_version',
-      side_effect=[lacros_outcome]
-    )
+        uprev_lib,
+        'uprev_workon_ebuild_to_version',
+        side_effect=[lacros_outcome])
     output = packages.uprev_lacros(None, self.refs, None)
     self.assertTrue(output.uprevved)
 
   def test_lacros_uprev_version_bump(self):
+    """Test lacros package uprev."""
     lacros_outcome = self.majorBumpOutcome(self.MOCK_LACROS_EBUILD_PATH)
     self.PatchObject(
-      uprev_lib,
-      'uprev_workon_ebuild_to_version',
-      side_effect=[lacros_outcome]
-    )
+        uprev_lib,
+        'uprev_workon_ebuild_to_version',
+        side_effect=[lacros_outcome])
     output = packages.uprev_lacros(None, self.refs, None)
     self.assertTrue(output.uprevved)
 
   def test_lacros_uprev_new_ebuild_created(self):
+    """Test lacros package uprev."""
     lacros_outcome = self.newEbuildCreatedOutcome(self.MOCK_LACROS_EBUILD_PATH)
     self.PatchObject(
-      uprev_lib,
-      'uprev_workon_ebuild_to_version',
-      side_effect=[lacros_outcome]
-    )
+        uprev_lib,
+        'uprev_workon_ebuild_to_version',
+        side_effect=[lacros_outcome])
     output = packages.uprev_lacros(None, self.refs, None)
     self.assertTrue(output.uprevved)
 
   def test_lacros_uprev_newer_version_exist(self):
+    """Test the newer version exists uprev should not happen."""
     lacros_outcome = self.newerVersionOutcome(self.MOCK_LACROS_EBUILD_PATH)
     self.PatchObject(
-      uprev_lib,
-      'uprev_workon_ebuild_to_version',
-      side_effect=[lacros_outcome]
-    )
+        uprev_lib,
+        'uprev_workon_ebuild_to_version',
+        side_effect=[lacros_outcome])
     output = packages.uprev_lacros(None, self.refs, None)
     self.assertFalse(output.uprevved)
 
   def test_lacros_uprev_same_version_exist(self):
+    """Test the same version exists uprev should not happen."""
     lacros_outcome = self.sameVersionOutcome(self.MOCK_LACROS_EBUILD_PATH)
     self.PatchObject(
-      uprev_lib,
-      'uprev_workon_ebuild_to_version',
-      side_effect=[lacros_outcome]
-    )
+        uprev_lib,
+        'uprev_workon_ebuild_to_version',
+        side_effect=[lacros_outcome])
     output = packages.uprev_lacros(None, self.refs, None)
     self.assertFalse(output.uprevved)
+
+
+class UprevLacrosInParallelTest(cros_test_lib.MockTestCase):
+  """Tests for uprev_lacros"""
+
+  def setUp(self):
+    self.refs = [
+        GitRef(path='/lacros', revision='abc123', ref='refs/tags/123.456.789.0')
+    ]
+    self.MOCK_LACROS_EBUILD_PATH = 'chromeos-lacros-123.456.789.0-r1.ebuild'
+
+  def revisionBumpOutcome(self, ebuild_path):
+    return uprev_lib.UprevResult(uprev_lib.Outcome.REVISION_BUMP, [ebuild_path])
+
+  def majorBumpOutcome(self, ebuild_path):
+    return uprev_lib.UprevResult(uprev_lib.Outcome.VERSION_BUMP, [ebuild_path])
+
+  def newerVersionOutcome(self, ebuild_path):
+    return uprev_lib.UprevResult(uprev_lib.Outcome.NEWER_VERSION_EXISTS,
+                                 [ebuild_path])
+
+  def sameVersionOutcome(self, ebuild_path):
+    return uprev_lib.UprevResult(uprev_lib.Outcome.SAME_VERSION_EXISTS,
+                                 [ebuild_path])
+
+  def newEbuildCreatedOutcome(self, ebuild_path):
+    return uprev_lib.UprevResult(uprev_lib.Outcome.NEW_EBUILD_CREATED,
+                                 [ebuild_path])
+
+  def test_lacros_uprev_fails(self):
+    """Test a lacros package uprev with no triggers"""
+    self.PatchObject(
+        uprev_lib, 'uprev_workon_ebuild_to_version', side_effect=[None])
+    with self.assertRaises(TypeError):
+      packages.uprev_lacros_in_parallel(None, [], None)
+
+  def test_lacros_uprev_revision_bump(self):
+    """Test lacros package uprev."""
+    lacros_outcome = self.revisionBumpOutcome(self.MOCK_LACROS_EBUILD_PATH)
+    self.PatchObject(
+        uprev_lib,
+        'uprev_workon_ebuild_to_version',
+        side_effect=[lacros_outcome])
+    output = packages.uprev_lacros_in_parallel(None, self.refs, None)
+    self.assertTrue(output.uprevved)
+
+  def test_lacros_uprev_version_bump(self):
+    """Test lacros package uprev."""
+    lacros_outcome = self.majorBumpOutcome(self.MOCK_LACROS_EBUILD_PATH)
+    self.PatchObject(
+        uprev_lib,
+        'uprev_workon_ebuild_to_version',
+        side_effect=[lacros_outcome])
+    output = packages.uprev_lacros_in_parallel(None, self.refs, None)
+    self.assertTrue(output.uprevved)
+
+  def test_lacros_uprev_new_ebuild_created(self):
+    """Test lacros package uprev."""
+    lacros_outcome = self.newEbuildCreatedOutcome(self.MOCK_LACROS_EBUILD_PATH)
+    self.PatchObject(
+        uprev_lib,
+        'uprev_workon_ebuild_to_version',
+        side_effect=[lacros_outcome])
+    output = packages.uprev_lacros_in_parallel(None, self.refs, None)
+    self.assertTrue(output.uprevved)
+
+  def test_lacros_uprev_newer_version_exist(self):
+    """Test the newer version exists uprev should not happen."""
+    lacros_outcome = self.newerVersionOutcome(self.MOCK_LACROS_EBUILD_PATH)
+    self.PatchObject(
+        uprev_lib,
+        'uprev_workon_ebuild_to_version',
+        side_effect=[lacros_outcome])
+    output = packages.uprev_lacros_in_parallel(None, self.refs, None)
+    self.assertFalse(output.uprevved)
+
+  def test_lacros_uprev_same_version_exist(self):
+    """Test the same version exists uprev should not happen."""
+    lacros_outcome = self.sameVersionOutcome(self.MOCK_LACROS_EBUILD_PATH)
+    self.PatchObject(
+        uprev_lib,
+        'uprev_workon_ebuild_to_version',
+        side_effect=[lacros_outcome])
+    output = packages.uprev_lacros_in_parallel(None, self.refs, None)
+    self.assertFalse(output.uprevved)
diff --git a/service/payload.py b/service/payload.py
index 1d1e17a..8f7bfbf 100644
--- a/service/payload.py
+++ b/service/payload.py
@@ -7,6 +7,7 @@
 from copy import deepcopy
 import os
 import re
+from typing import Optional, Tuple, Union
 
 from chromite.lib import chroot_util
 from chromite.lib.paygen import gspaths
@@ -32,25 +33,27 @@
   """Value object to hold the GeneratePayload configuration options."""
 
   def __init__(self,
-               tgt_image=None,
-               src_image=None,
-               dest_bucket=None,
-               verify=True,
-               keyset=None,
-               upload=True,
-               cache_dir=None):
+               tgt_image: Optional[Union[payload_pb2.UnsignedImage,
+                                         payload_pb2.SignedImage,
+                                         payload_pb2.DLCImage]] = None,
+               src_image: Optional[Union[payload_pb2.UnsignedImage,
+                                         payload_pb2.SignedImage,
+                                         payload_pb2.DLCImage]] = None,
+               dest_bucket: Optional[str] = None,
+               minios: bool = False,
+               verify: bool = True,
+               upload: bool = True,
+               cache_dir: Optional[str] = None):
     """Init method, sets up all the paths and configuration.
 
     Args:
-      tgt_image (UnsignedImage, SignedImage, or DLCImage):
-          Proto for destination image.
-      src_image (UnsignedImage, SignedImage, DLCImage, or None):
-          Proto for source image.
-      dest_bucket (str): Destination bucket to place the final artifacts in.
-      verify (bool): If delta is made, verify the integrity of the payload.
-      keyset (str): The key to sign the image with.
-      upload (bool): Whether the payload generation results should be uploaded.
-      cache_dir (str): The cache dir for paygen to use or None for default.
+      tgt_image: Proto for destination image.
+      src_image: Proto for source image.
+      dest_bucket: Destination bucket to place the final artifacts in.
+      minios: Whether the payload is for the image's miniOS partition.
+      verify: If delta is made, verify the integrity of the payload.
+      upload: Whether the payload generation results should be uploaded.
+      cache_dir: The cache dir for paygen to use or None for default.
     """
 
     # Set when we call GeneratePayload on this object.
@@ -58,8 +61,8 @@
     self.tgt_image = tgt_image
     self.src_image = src_image
     self.dest_bucket = dest_bucket
+    self.minios = minios
     self.verify = verify
-    self.keyset = keyset
     self.upload = upload
     self.delta_type = 'delta' if self.src_image else 'full'
     self.image_type = _ImageTypeToStr(tgt_image.image_type)
@@ -67,10 +70,12 @@
 
     # This block ensures that we have paths to the correct perm of images.
     src_image_path = None
+    tgt_key = None
     if isinstance(self.tgt_image, payload_pb2.UnsignedImage):
       tgt_image_path = _GenUnsignedGSPath(self.tgt_image, self.image_type)
     elif isinstance(self.tgt_image, payload_pb2.SignedImage):
       tgt_image_path = _GenSignedGSPath(self.tgt_image, self.image_type)
+      tgt_key = self.tgt_image.key
     elif isinstance(self.tgt_image, payload_pb2.DLCImage):
       tgt_image_path = _GenDLCImageGSPath(self.tgt_image)
     if self.delta_type == 'delta':
@@ -81,7 +86,6 @@
       elif isinstance(self.tgt_image, payload_pb2.DLCImage):
         src_image_path = _GenDLCImageGSPath(self.src_image)
 
-
     # Set your output location.
     if self.upload:
       payload_build = deepcopy(tgt_image_path.build)
@@ -89,29 +93,31 @@
       payload_output_uri = gspaths.ChromeosReleases.PayloadUri(
           build=payload_build,
           random_str=None,
-          key=self.keyset,
+          key=tgt_key,
           src_version=src_image_path.build.version if src_image else None,
       )
     else:
       payload_output_uri = None
 
     self.payload = gspaths.Payload(
-        tgt_image=tgt_image_path, src_image=src_image_path,
+        tgt_image=tgt_image_path, src_image=src_image_path, minios=self.minios,
         uri=payload_output_uri)
 
 
-  def GeneratePayload(self):
+  def GeneratePayload(self) -> Tuple[str, str]:
     """Do payload generation (& maybe sign) on Google Storage CrOS images.
 
     Returns:
-      A tuple of (string, string) containing:
+      A tuple of containing:
           The location of the local generated artifact.
             (e.g. /tmp/wdjaio/delta.bin)
           The remote location that the payload was uploaded or None.
             (e.g. 'gs://cr/beta-channel/coral/12345.0.1/payloads/...')
-    """
-    should_sign = self.keyset != ''
 
+    Raises:
+      paygen_payload_lib.PayloadGenerationSkippedException: If paygen was
+          skipped for any reason.
+    """
     # Leave the generated artifact local. This is ok because if we're testing
     # it's likely we want the artifact anyway, and in production this is ran on
     # single shot bots in the context of an overlayfs and will get cleaned up
@@ -120,7 +126,7 @@
       self.paygen = paygen_payload_lib.PaygenPayload(
           self.payload,
           temp_dir,
-          sign=should_sign,
+          sign=True,
           verify=self.verify,
           upload=self.upload,
           cache_dir=self.cache_dir)
@@ -132,30 +138,19 @@
       return (local_path, remote_uri)
 
 
-class GeneratePayloadResult(object):
-  """Value object to report GeneratePayload results."""
-
-  def __init__(self, return_code):
-    """Initialize a GeneratePayloadResult.
-
-    Args:
-      return_code (bool): The return code of the GeneratePayload operation.
-    """
-    self.success = return_code == 0
-
-
-def _ImageTypeToStr(image_type_n):
+def _ImageTypeToStr(image_type_n: int) -> str:
   """The numeral image type enum in proto to lowercase string."""
   ret = common_pb2.ImageType.Name(image_type_n).lower()
   return re.sub('^image_type_', '', ret)
 
 
-def _GenSignedGSPath(image, image_type):
+def _GenSignedGSPath(image: payload_pb2.SignedImage,
+                     image_type: str) -> gspaths.Image:
   """Take a SignedImage_pb2 and return a gspaths.Image.
 
   Args:
-    image (SignedImage_pb2): The build to create the gspath from.
-    image_type (string): The image type, either "recovery" or "base".
+    image: The build to create the gspath from.
+    image_type: The image type, either "recovery" or "base".
 
   Returns:
     A gspaths.Image instance.
@@ -175,12 +170,13 @@
                        uri=build_uri)
 
 
-def _GenUnsignedGSPath(image, image_type):
+def _GenUnsignedGSPath(image: payload_pb2.UnsignedImage,
+                       image_type: str) -> gspaths.UnsignedImageArchive:
   """Take an UnsignedImage_pb2 and return a gspaths.UnsignedImageArchive.
 
   Args:
-    image (UnsignedImage_pb2): The build to create the gspath from.
-    image_type (string): The image type, either "recovery" or "test".
+    image: The build to create the gspath from.
+    image_type: The image type, either "recovery" or "test".
 
   Returns:
     A gspaths.UnsignedImageArchive instance.
@@ -201,11 +197,11 @@
                                       uri=build_uri)
 
 
-def _GenDLCImageGSPath(image):
+def _GenDLCImageGSPath(image: payload_pb2.DLCImage) -> gspaths.DLCImage:
   """Take a DLCImage_pb2 and return a gspaths.DLCImage.
 
   Args:
-    image (DLCImage_pb2): The dlc image to create the gspath from.
+    image: The dlc image to create the gspath from.
 
   Returns:
     A gspaths.DLCImage instance.
diff --git a/service/payload_unittest.py b/service/payload_unittest.py
index 1a92307..1665d76 100644
--- a/service/payload_unittest.py
+++ b/service/payload_unittest.py
@@ -41,7 +41,6 @@
         src_image=src_image,
         dest_bucket='test',
         verify=True,
-        keyset=None,
         upload=True)
 
     payload_config.GeneratePayload()
@@ -60,7 +59,6 @@
         src_image=src_image,
         dest_bucket='test',
         verify=True,
-        keyset=None,
         upload=True)
 
     payload_config.GeneratePayload()
@@ -77,17 +75,23 @@
         src_image=None,
         dest_bucket='test',
         verify=True,
-        keyset=None,
         upload=True)
 
     payload_config.GeneratePayload()
 
-# TODO(crbug/1155212): Fix aliased enum value.
-# class PayloadUtilitiesTest(cros_test_lib.TestCase):
-#   """Test utilities related to payloads."""
-#
-#   def testImageType(self):
-#     """Test _ImageTypeToStr works."""
-#     # pylint: disable=protected-access
-#     self.assertEqual('image_type_base', payload._ImageTypeToStr(1))
-#     # pylint: enable=protected-access
+  def testMiniOS(self):
+    """Test the happy path on a miniOS payload."""
+
+    # Image def.
+    tgt_image = payload_pb2.UnsignedImage(
+        build=self.tgt_build, image_type='IMAGE_TYPE_BASE', milestone='R80')
+
+    payload_config = payload.PayloadConfig(
+        tgt_image=tgt_image,
+        src_image=None,
+        dest_bucket='test',
+        minios=True,
+        verify=True,
+        upload=True)
+
+    payload_config.GeneratePayload()
diff --git a/service/sdk.py b/service/sdk.py
index 9a7a0b9..3a7cf1d 100644
--- a/service/sdk.py
+++ b/service/sdk.py
@@ -6,6 +6,7 @@
 
 import logging
 import os
+from typing import List, Optional, TYPE_CHECKING
 import uuid
 
 from chromite.lib import constants
@@ -13,6 +14,9 @@
 from chromite.lib import cros_sdk_lib
 from chromite.lib import osutils
 
+if TYPE_CHECKING:
+  from chromite.lib import chroot_lib
+
 
 class Error(Exception):
   """Base module error."""
@@ -21,7 +25,8 @@
 class UnmountError(Error):
   """An error raised when unmount fails."""
 
-  def __init__(self, path, cmd_error=None, fs_debug=None):
+  def __init__(self, path: str, cmd_error: cros_build_lib.RunCommandError,
+               fs_debug: cros_sdk_lib.FileSystemDebugInfo):
     super().__init__(path, cmd_error, fs_debug)
     self.path = path
     self.cmd_error = cmd_error
@@ -37,29 +42,36 @@
 class CreateArguments(object):
   """Value object to handle the chroot creation arguments."""
 
-  def __init__(self, replace=False, bootstrap=False, use_image=True,
-               chroot_path=None, cache_dir=None):
+  def __init__(self,
+               replace: bool = False,
+               bootstrap: bool = False,
+               use_image: bool = True,
+               chroot_path: Optional[str] = None,
+               cache_dir: Optional[str] = None,
+               sdk_version: Optional[str] = None):
     """Create arguments init.
 
     Args:
-      replace (bool): Whether an existing chroot should be deleted.
-      bootstrap (bool): Whether to build the SDK from source.
-      use_image (bool): Whether to mount the chroot on a loopback image or
-        create it directly in a directory.
+      replace: Whether an existing chroot should be deleted.
+      bootstrap: Whether to build the SDK from source.
+      use_image: Whether to mount the chroot on a loopback image or create it
+        directly in a directory.
       chroot_path: Path to where the chroot should be reside.
       cache_dir: Alternative directory to use as a cache for the chroot.
+      sdk_version: Specific SDK version to use, e.g. 2022.01.20.073008.
     """
     self.replace = replace
     self.bootstrap = bootstrap
     self.use_image = use_image
     self.chroot_path = chroot_path
     self.cache_dir = cache_dir
+    self.sdk_version = sdk_version
 
-  def GetArgList(self):
+  def GetArgList(self) -> List[str]:
     """Get the list of the corresponding command line arguments.
 
     Returns:
-      list - The list of the corresponding command line arguments.
+      The list of the corresponding command line arguments.
     """
     args = []
 
@@ -82,6 +94,9 @@
     if self.chroot_path:
       args.extend(['--chroot', self.chroot_path])
 
+    if self.sdk_version:
+      args.extend(['--sdk-version', self.sdk_version])
+
     return args
 
 
@@ -89,26 +104,26 @@
   """Value object to handle the update arguments."""
 
   def __init__(self,
-               build_source=False,
-               toolchain_targets=None,
-               toolchain_changed=False):
+               build_source: bool = False,
+               toolchain_targets: Optional[List[str]] = None,
+               toolchain_changed: bool = False):
     """Update arguments init.
 
     Args:
-      build_source (bool): Whether to build the source or use prebuilts.
-      toolchain_targets (list): The list of build targets whose toolchains
-        should be updated.
-      toolchain_changed (bool): Whether a toolchain change has occurred. Implies
+      build_source: Whether to build the source or use prebuilts.
+      toolchain_targets: The list of build targets whose toolchains should be
+        updated.
+      toolchain_changed: Whether a toolchain change has occurred. Implies
         build_source.
     """
     self.build_source = build_source or toolchain_changed
     self.toolchain_targets = toolchain_targets
 
-  def GetArgList(self):
+  def GetArgList(self) -> List[str]:
     """Get the list of the corresponding command line arguments.
 
     Returns:
-      list - The list of the corresponding command line arguments.
+      The list of the corresponding command line arguments.
     """
     args = []
 
@@ -120,7 +135,14 @@
     return args
 
 
-def Clean(chroot, images=False, sysroots=False, tmp=False):
+def Clean(chroot: Optional['chroot_lib.Chroot'],
+          images: bool = False,
+          sysroots: bool = False,
+          tmp: bool = False,
+          safe: bool = False,
+          cache: bool = False,
+          logs: bool = False,
+          workdirs: bool = False) -> None:
   """Clean the chroot.
 
   See:
@@ -128,34 +150,47 @@
 
   Args:
     chroot: The chroot to clean.
-    images (bool): Remove all built images.
-    sysroots (bool): Remove all of the sysroots.
-    tmp (bool): Clean the tmp/ directory.
+    images: Remove all built images.
+    sysroots: Remove all of the sysroots.
+    tmp: Clean the tmp/ directory.
+    safe: Clean all produced artifacts.
+    cache: Clean the shared cache.
+    logs: Clean up various logs.
+    workdirs: Clean out various package build work directories.
   """
-  if not images and not sysroots and not tmp:
+  if not (images or sysroots or tmp or safe or cache or logs or workdirs):
+    # Nothing specified to clean.
     return
 
-  cmd = ['cros', 'clean']
+  cmd = ['cros', 'clean', '--debug']
   if chroot:
     cmd.extend(['--sdk-path', chroot.path])
+  if safe:
+    cmd.append('--safe')
   if images:
     cmd.append('--images')
   if sysroots:
     cmd.append('--sysroots')
   if tmp:
     cmd.append('--chroot-tmp')
+  if cache:
+    cmd.append('--cache')
+  if logs:
+    cmd.append('--logs')
+  if workdirs:
+    cmd.append('--workdirs')
 
   cros_build_lib.run(cmd)
 
 
-def Create(arguments):
+def Create(arguments: CreateArguments) -> Optional[int]:
   """Create or replace the chroot.
 
   Args:
-    arguments (CreateArguments): The various arguments to create a chroot.
+    arguments: The various arguments to create a chroot.
 
   Returns:
-    int - The version of the resulting chroot.
+    The version of the resulting chroot.
   """
   cros_build_lib.AssertOutsideChroot()
 
@@ -189,13 +224,13 @@
   return GetChrootVersion(arguments.chroot_path)
 
 
-def Delete(chroot=None, force=False):
+def Delete(chroot: Optional['chroot_lib.Chroot'] = None,
+           force: bool = False) -> None:
   """Delete the chroot.
 
   Args:
-    chroot (chroot_lib.Chroot): The chroot being deleted, or None for the
-      default chroot.
-    force: Boolean that applies the --force option.
+    chroot: The chroot being deleted, or None for the default chroot.
+    force: Whether to apply the --force option.
   """
   # Delete the chroot itself.
   logging.info('Removing the SDK.')
@@ -212,12 +247,11 @@
   Clean(chroot, images=True)
 
 
-def Unmount(chroot=None):
+def Unmount(chroot: Optional['chroot_lib.Chroot'] = None) -> None:
   """Unmount the chroot.
 
   Args:
-    chroot (chroot_lib.Chroot): The chroot being unmounted, or None for the
-      default chroot.
+    chroot: The chroot being unmounted, or None for the default chroot.
   """
   logging.info('Unmounting the chroot.')
   cmd = [os.path.join(constants.CHROMITE_BIN_DIR, 'cros_sdk'), '--unmount']
@@ -227,7 +261,7 @@
   cros_build_lib.run(cmd)
 
 
-def UnmountPath(path: str):
+def UnmountPath(path: str) -> None:
   """Unmount the specified path.
 
   Args:
@@ -241,14 +275,14 @@
     raise UnmountError(path, e, fs_debug)
 
 
-def GetChrootVersion(chroot_path=None):
+def GetChrootVersion(chroot_path: Optional[str] = None) -> Optional[int]:
   """Get the chroot version.
 
   Args:
-    chroot_path (str|None): The chroot path.
+    chroot_path: The chroot path, or None for the default chroot path.
 
   Returns:
-    int|None - The version of the chroot if the chroot is valid, else None.
+    The version of the chroot if the chroot is valid, else None.
   """
   if chroot_path:
     path = chroot_path
@@ -260,14 +294,15 @@
   return cros_sdk_lib.GetChrootVersion(path)
 
 
-def Update(arguments):
+def Update(arguments: UpdateArguments) -> Optional[int]:
   """Update the chroot.
 
   Args:
-    arguments (UpdateArguments): The various arguments for updating a chroot.
+    arguments: The various arguments for updating a chroot.
 
   Returns:
-    int - The version of the chroot after the update.
+    The version of the chroot after the update, or None if the chroot is
+      invalid.
   """
   # TODO: This should be able to be run either in or out of the chroot.
   cros_build_lib.AssertInsideChroot()
@@ -286,16 +321,17 @@
   return GetChrootVersion()
 
 
-def CreateSnapshot(chroot=None, replace_if_needed=False):
+def CreateSnapshot(chroot: Optional['chroot_lib.Chroot'] = None,
+                   replace_if_needed: bool = False) -> str:
   """Create a logical volume snapshot of a chroot.
 
   Args:
-    chroot (chroot_lib.Chroot): The chroot to perform the operation on.
-    replace_if_needed (bool): If true, will replace the existing chroot with
-      a new one capable of being mounted as a loopback image if needed.
+    chroot: The chroot to perform the operation on.
+    replace_if_needed: If True, will replace the existing chroot with a new one
+      capable of being mounted as a loopback image if needed.
 
   Returns:
-    str - The name of the snapshot created.
+    The name of the snapshot created.
   """
   _EnsureSnapshottableState(chroot, replace=replace_if_needed)
 
@@ -315,13 +351,15 @@
   return snapshot_token
 
 
-def RestoreSnapshot(snapshot_token, chroot=None):
+def RestoreSnapshot(snapshot_token: str,
+                    chroot: Optional['chroot_lib.Chroot'] = None) -> None:
   """Restore a logical volume snapshot of a chroot.
 
   Args:
-    snapshot_token (str): The name of the snapshot to restore. Typically an
-      opaque generated name returned from `CreateSnapshot`.
-    chroot (chroot_lib.Chroot): The chroot to perform the operation on.
+    snapshot_token: The name of the snapshot to restore. Typically an opaque
+      generated name returned from `CreateSnapshot`.
+    chroot: The chroot to perform the operation on, or None for the default
+      chroot.
   """
   # Unmount to clean up stale processes that may still be in the chroot, in
   # order to prevent 'device busy' errors from umount.
@@ -339,13 +377,15 @@
   cros_build_lib.run(cmd)
 
 
-def _EnsureSnapshottableState(chroot=None, replace=False):
+def _EnsureSnapshottableState(chroot: Optional['chroot_lib.Chroot'] = None,
+                              replace: bool = False) -> None:
   """Ensures that a chroot is in a capable state to create an LVM snapshot.
 
   Args:
-    chroot (chroot_lib.Chroot): The chroot to perform the operation on.
-    replace (bool): If true, will replace the existing chroot with a new one
-      capable of being mounted as a loopback image if needed.
+    chroot: The chroot to perform the operation on, or None for the default
+      chroot.
+    replace: If true, will replace the existing chroot with a new one capable of
+      being mounted as a loopback image if needed.
   """
   cmd = [
       os.path.join(constants.CHROMITE_BIN_DIR, 'cros_sdk'),
diff --git a/service/sdk_unittest.py b/service/sdk_unittest.py
index 6832da5..634be43 100644
--- a/service/sdk_unittest.py
+++ b/service/sdk_unittest.py
@@ -28,9 +28,10 @@
     self.assertIn('--create', self._GetArgsList(replace=False))
 
     # Check the other flags get added when the correct argument passed.
-    self.assertListEqual(['--create', '--use-image'],
+    self.assertListEqual(['--create', '--use-image', '--sdk-version', 'foo'],
                          self._GetArgsList(
-                             replace=False, bootstrap=False, use_image=True))
+                             replace=False, bootstrap=False, use_image=True,
+                             sdk_version='foo'))
 
     self.assertListEqual(['--create', '--bootstrap', '--nouse-image'],
                          self._GetArgsList(
diff --git a/service/sysroot.py b/service/sysroot.py
index fc87c56..1c11b22 100644
--- a/service/sysroot.py
+++ b/service/sysroot.py
@@ -10,12 +10,10 @@
 import os
 import shutil
 import tempfile
-from typing import List, NamedTuple
+from typing import Dict, Generator, List, NamedTuple, Optional, TYPE_CHECKING
 import urllib
 
-from chromite.lib import build_target_lib
 from chromite.lib import cache
-from chromite.lib import chroot_lib
 from chromite.lib import constants
 from chromite.lib import cros_build_lib
 from chromite.lib import osutils
@@ -24,6 +22,11 @@
 from chromite.lib import workon_helper
 from chromite.utils import metrics
 
+if TYPE_CHECKING:
+  from chromite.lib import binpkg
+  from chromite.lib import build_target_lib
+  from chromite.lib import chroot_lib
+
 
 class Error(Exception):
   """Base error class for the module."""
@@ -48,28 +51,37 @@
 class SetupBoardRunConfig(object):
   """Value object for full setup board run configurations."""
 
-  def __init__(self, set_default=False, force=False, usepkg=True, jobs=None,
-               regen_configs=False, quiet=False, update_toolchain=True,
-               upgrade_chroot=True, init_board_pkgs=True, local_build=False,
-               toolchain_changed=False, package_indexes=None,
-               expanded_binhost_inheritance: bool = False):
+  def __init__(
+      self,
+      set_default: bool = False,
+      force: bool = False,
+      usepkg: bool = True,
+      jobs: Optional[int] = None,
+      regen_configs: bool = False,
+      quiet: bool = False,
+      update_toolchain: bool = True,
+      upgrade_chroot: bool = True,
+      init_board_pkgs: bool = True,
+      local_build: bool = False,
+      toolchain_changed: bool = False,
+      package_indexes: Optional[List['binpkg.PackageIndexInfo']] = None,
+      expanded_binhost_inheritance: bool = False):
     """Initialize method.
 
     Args:
-      set_default (bool): Whether to set the passed board as the default.
-      force (bool): Force a new sysroot creation when it already exists.
-      usepkg (bool): Whether to use binary packages to bootstrap.
-      jobs (int): Max number of simultaneous packages to build.
-      regen_configs (bool): Whether to only regen the configs.
-      quiet (bool): Whether to print notification when sysroot exists.
-      update_toolchain (bool): Update the toolchain?
-      upgrade_chroot (bool): Upgrade the chroot before building?
-      init_board_pkgs (bool): Emerging packages to sysroot?
-      local_build (bool): Bootstrap only from local packages?
-      toolchain_changed (bool): Has a toolchain change occurred? Implies
-        'force'.
-      package_indexes (list[PackageIndexInfo]): List of information about
-        available prebuilts, youngest first, or None.
+      set_default: Whether to set the passed board as the default.
+      force: Force a new sysroot creation when it already exists.
+      usepkg: Whether to use binary packages to bootstrap.
+      jobs: Max number of simultaneous packages to build.
+      regen_configs: Whether to only regen the configs.
+      quiet: Whether to print notification when sysroot exists.
+      update_toolchain: Update the toolchain?
+      upgrade_chroot: Upgrade the chroot before building?
+      init_board_pkgs: Emerging packages to sysroot?
+      local_build: Bootstrap only from local packages?
+      toolchain_changed: Has a toolchain change occurred? Implies 'force'.
+      package_indexes: List of information about available prebuilts, youngest
+          first, or None.
       expanded_binhost_inheritance: Allow expanded binhost inheritance.
     """
     self.set_default = set_default
@@ -85,11 +97,11 @@
     self.package_indexes = package_indexes or []
     self.expanded_binhost_inheritance = expanded_binhost_inheritance
 
-  def GetUpdateChrootArgs(self):
+  def GetUpdateChrootArgs(self) -> List[str]:
     """Create a list containing the relevant update_chroot arguments.
 
     Returns:
-      list[str]
+      The list of arguments
     """
     args = []
     if self.usepkg:
@@ -109,34 +121,37 @@
 class BuildPackagesRunConfig(object):
   """Value object to hold build packages run configs."""
 
-  def __init__(self,
-               usepkg=True,
-               install_debug_symbols=False,
-               packages=None,
-               use_flags=None,
-               use_goma=False,
-               incremental_build=True,
-               package_indexes=None,
-               expanded_binhosts: bool = False,
-               setup_board: bool = True,
-               dryrun: bool = False):
+  def __init__(
+      self,
+      usepkg: bool = True,
+      install_debug_symbols: bool = False,
+      packages: Optional[List[str]] = None,
+      use_flags: Optional[List[str]] = None,
+      use_goma: bool = False,
+      use_remoteexec: bool = False,
+      incremental_build: bool = True,
+      package_indexes: Optional[List['binpkg.PackageIndexInfo']] = None,
+      expanded_binhosts: bool = False,
+      setup_board: bool = True,
+      dryrun: bool = False):
     """Init method.
 
     Args:
-      usepkg (bool): Whether to use binpkgs or build from source. False
-        currently triggers a local build, which will enable local reuse.
-      install_debug_symbols (bool): Whether to include the debug symbols for all
+      usepkg: Whether to use binpkgs or build from source. False currently
+        triggers a local build, which will enable local reuse.
+      install_debug_symbols: Whether to include the debug symbols for all
         packages.
-      packages (list[str]|None): The list of packages to install, by default
-        install all packages for the target.
-      use_flags (list[str]|None): A list of use flags to set.
-      use_goma (bool): Whether to enable goma.
-      incremental_build (bool): Whether to treat the build as an incremental
-        build or a fresh build. Always treating it as an incremental build is
-        safe, but certain operations can be faster when we know we are doing
-        a fresh build.
-      package_indexes (list[PackageIndexInfo]): List of information about
-        available prebuilts, youngest first, or None.
+      packages: The list of packages to install, by default install all packages
+        for the target.
+      use_flags: A list of use flags to set.
+      use_goma: Whether to enable goma.
+      use_remoteexec: Whether to use RBE for remoteexec.
+      incremental_build: Whether to treat the build as an incremental build or a
+        fresh build. Always treating it as an incremental build is safe, but
+        certain operations can be faster when we know we are doing a fresh
+        build.
+      package_indexes: List of information about available prebuilts, youngest
+        first, or None.
       expanded_binhosts: Whether to enable/disable the expanded binhost
         inheritance feature for the sysroot.
       setup_board: Whether to run setup_board in build_packages.
@@ -147,13 +162,14 @@
     self.packages = packages
     self.use_flags = use_flags
     self.use_goma = use_goma
+    self.use_remoteexec = use_remoteexec
     self.is_incremental = incremental_build
     self.package_indexes = package_indexes or []
     self.expanded_binhosts = expanded_binhosts
     self.setup_board = setup_board
     self.dryrun = dryrun
 
-  def GetBuildPackagesArgs(self):
+  def GetBuildPackagesArgs(self) -> List[str]:
     """Get the build_packages script arguments."""
     # Defaults for the builder.
     # TODO(saklein): Parametrize/rework the defaults when build_packages is
@@ -174,6 +190,9 @@
     if self.use_goma:
       args.append('--run_goma')
 
+    if self.use_remoteexec:
+      args.append('--run_remoteexec')
+
     if not self.is_incremental:
       args.append('--nowithrevdeps')
 
@@ -193,11 +212,11 @@
 
     return args
 
-  def HasUseFlags(self):
+  def HasUseFlags(self) -> bool:
     """Check if we have use flags."""
     return bool(self.use_flags)
 
-  def GetUseFlags(self):
+  def GetUseFlags(self) -> Optional[str]:
     """Get the use flags as a single string."""
     use_flags = self.use_flags
     if use_flags:
@@ -212,7 +231,7 @@
 
     return None
 
-  def GetEnv(self):
+  def GetEnv(self) -> Dict[str, str]:
     """Get the env from this config."""
     env = {}
     if self.HasUseFlags():
@@ -221,6 +240,9 @@
     if self.use_goma:
       env['USE_GOMA'] = 'true'
 
+    if self.use_remoteexec:
+      env['USE_REMOTEEXEC'] = 'true'
+
     if self.package_indexes:
       env['PORTAGE_BINHOST'] = ' '.join(
           x.location for x in reversed(self.package_indexes))
@@ -228,15 +250,17 @@
     return env
 
 
-def SetupBoard(target, accept_licenses=None, run_configs=None):
+def SetupBoard(target: 'build_target_lib.BuildTarget',
+               accept_licenses: Optional[str] = None,
+               run_configs: Optional[SetupBoardRunConfig] = None) -> None:
   """Run the full process to setup a board's sysroot.
 
   This is the entry point to run the setup_board script.
 
   Args:
-    target (build_target_lib.BuildTarget): The build target configuration.
-    accept_licenses (str|None): The additional licenses to accept.
-    run_configs (SetupBoardRunConfig): The run configs.
+    target: The build target configuration.
+    accept_licenses: The additional licenses to accept.
+    run_configs: The run configs.
 
   Raises:
     sysroot_lib.ToolchainInstallError when the toolchain fails to install.
@@ -257,26 +281,27 @@
   InstallToolchain(target, sysroot, run_configs)
 
 
-def Create(target, run_configs, accept_licenses):
+def Create(target: 'build_target_lib.BuildTarget',
+           run_configs: SetupBoardRunConfig,
+           accept_licenses: Optional[str]) -> sysroot_lib.Sysroot:
   """Create a sysroot.
 
   This entry point is the subset of the full setup process that does the
   creation and configuration of a sysroot, including installing portage.
 
   Args:
-    target (build_target.BuildTarget): The build target being installed in the
-      sysroot being created.
-    run_configs (SetupBoardRunConfig): The run configs.
-    accept_licenses (str|None): The additional licenses to accept.
+    target: The build target being installed in the sysroot being created.
+    run_configs: The run configs.
+    accept_licenses: The additional licenses to accept.
   """
   cros_build_lib.AssertInsideChroot()
 
   sysroot = sysroot_lib.Sysroot(target.root)
 
   if sysroot.Exists() and not run_configs.force and not run_configs.quiet:
-    logging.warning('Board output directory already exists: %s\n'
-                    'Use --force to clobber the board root and start again.',
-                    sysroot.path)
+    logging.warning(
+        'Board output directory already exists: %s\n'
+        'Use --force to clobber the board root and start again.', sysroot.path)
 
   # Override regen_configs setting to force full setup run if the sysroot does
   # not exist.
@@ -286,8 +311,10 @@
   # chroot update is explicitly disabled.
   if run_configs.update_chroot:
     logging.info('Updating chroot.')
-    update_chroot = [os.path.join(constants.CROSUTILS_DIR, 'update_chroot'),
-                     '--toolchain_boards', target.name]
+    update_chroot = [
+        os.path.join(constants.CROSUTILS_DIR, 'update_chroot'),
+        '--toolchain_boards', target.name
+    ]
     update_chroot += run_configs.GetUpdateChrootArgs()
     try:
       cros_build_lib.run(update_chroot)
@@ -332,27 +359,30 @@
   return sysroot
 
 
-def GenerateArchive(output_dir, build_target_name, pkg_list):
+def GenerateArchive(output_dir: str, build_target_name: str,
+                    pkg_list: List[str]) -> str:
   """Generate a sysroot tarball for informational builders.
 
   Args:
-    output_dir (string): Directory to contain the created the sysroot.
-    build_target_name (string): The build target for the sysroot being created.
-    pkg_list (list[string]|None): List of 'category/package' package strings.
+    output_dir: Directory to contain the created the sysroot.
+    build_target_name: The build target for the sysroot being created.
+    pkg_list: List of 'category/package' package strings.
 
   Returns:
     Path to the sysroot tar file.
   """
-  cmd = ['cros_generate_sysroot',
-         '--out-file', constants.TARGET_SYSROOT_TAR,
-         '--out-dir', output_dir,
-         '--board', build_target_name,
-         '--package', ' '.join(pkg_list)]
+  cmd = [
+      'cros_generate_sysroot', '--out-file', constants.TARGET_SYSROOT_TAR,
+      '--out-dir', output_dir, '--board', build_target_name, '--package',
+      ' '.join(pkg_list)
+  ]
   cros_build_lib.run(cmd, cwd=constants.SOURCE_ROOT)
   return os.path.join(output_dir, constants.TARGET_SYSROOT_TAR)
 
 
-def CreateSimpleChromeSysroot(chroot, _sysroot_class, build_target, output_dir):
+def CreateSimpleChromeSysroot(chroot: 'chroot_lib.Chroot', _sysroot_class,
+                              build_target: 'build_target_lib.BuildTarget',
+                              output_dir: str) -> str:
   """Create a sysroot for SimpleChrome to use.
 
   Args:
@@ -364,10 +394,16 @@
   Returns:
     Path to the sysroot tar file.
   """
-  cmd = ['cros_generate_sysroot', '--out-dir', '/tmp', '--board',
-         build_target.name, '--deps-only', '--package', constants.CHROME_CP]
-  cros_build_lib.run(cmd, cwd=constants.SOURCE_ROOT, enter_chroot=True,
-                     chroot_args=chroot.get_enter_args(), extra_env=chroot.env)
+  cmd = [
+      'cros_generate_sysroot', '--out-dir', '/tmp', '--board',
+      build_target.name, '--deps-only', '--package', constants.CHROME_CP
+  ]
+  cros_build_lib.run(
+      cmd,
+      cwd=constants.SOURCE_ROOT,
+      enter_chroot=True,
+      chroot_args=chroot.get_enter_args(),
+      extra_env=chroot.env)
 
   # Move the artifact out of the chroot.
   sysroot_tar_path = os.path.join(
@@ -376,17 +412,19 @@
   return os.path.join(output_dir, constants.CHROME_SYSROOT_TAR)
 
 
-def CreateChromeEbuildEnv(chroot, sysroot_class, _build_target, output_dir):
+def CreateChromeEbuildEnv(chroot: 'chroot_lib.Chroot',
+                          sysroot_class: sysroot_lib.Sysroot, _build_target,
+                          output_dir: str) -> Optional[str]:
   """Generate Chrome ebuild environment.
 
   Args:
     chroot: The chroot class used for these artifacts.
-    sysroot_class (sysroot_lib.Sysroot): The sysroot where the original
-      environment archive can be found.
-    output_dir (str): Where the result should be stored.
+    sysroot_class: The sysroot where the original environment archive can be
+      found.
+    output_dir: Where the result should be stored.
 
   Returns:
-    str: The path to the archive, or None.
+    The path to the archive, or None.
   """
   pkg_dir = chroot.full_path(sysroot_class.path, portage_util.VDB_PATH)
   files = glob.glob(os.path.join(pkg_dir, constants.CHROME_CP) + '-*')
@@ -405,26 +443,25 @@
     # Convert from bzip2 to tar format.
     bzip2 = cros_build_lib.FindCompressor(cros_build_lib.COMP_BZIP2)
     tempdir_tar_path = os.path.join(tempdir, constants.CHROME_ENV_FILE)
-    cros_build_lib.run([bzip2, '-d', env_bzip, '-c'],
-                       stdout=tempdir_tar_path)
+    cros_build_lib.run([bzip2, '-d', env_bzip, '-c'], stdout=tempdir_tar_path)
 
     cros_build_lib.CreateTarball(result_path, tempdir)
 
   return result_path
 
 
-def InstallToolchain(target, sysroot, run_configs):
+def InstallToolchain(target: 'build_target_lib.BuildTarget',
+                     sysroot: sysroot_lib.Sysroot,
+                     run_configs: SetupBoardRunConfig) -> None:
   """Update the toolchain to a sysroot.
 
   This entry point just installs the target's toolchain into the sysroot.
   Everything else must have been done already for this to be successful.
 
   Args:
-    target (build_target_lib.BuildTarget): The target whose toolchain is being
-      installed.
-    sysroot (sysroot_lib.Sysroot): The sysroot where the toolchain is being
-      installed.
-    run_configs (SetupBoardRunConfig): The run configs.
+    target: The target whose toolchain is being installed.
+    sysroot: The sysroot where the toolchain is being installed.
+    run_configs: The run configs.
   """
   cros_build_lib.AssertInsideChroot()
   if not sysroot.Exists():
@@ -440,20 +477,22 @@
     _InstallToolchain(sysroot, target, local_init=local_init)
 
 
-def BuildPackages(target, sysroot, run_configs):
+def BuildPackages(target: 'build_target_lib.BuildTarget',
+                  sysroot: sysroot_lib.Sysroot,
+                  run_configs: BuildPackagesRunConfig) -> None:
   """Build and install packages into a sysroot.
 
   Args:
-    target (build_target_lib.BuildTarget): The target whose packages are being
-      installed.
-    sysroot (sysroot_lib.Sysroot): The sysroot where the packages are being
-      installed.
-    run_configs (BuildPackagesRunConfig): The run configs.
+    target: The target whose packages are being installed.
+    sysroot: The sysroot where the packages are being installed.
+    run_configs: The run configs.
   """
   cros_build_lib.AssertInsideChroot()
 
-  cmd = [os.path.join(constants.CROSUTILS_DIR, 'build_packages'),
-         '--board', target.name, '--board_root', sysroot.path]
+  cmd = [
+      os.path.join(constants.CROSUTILS_DIR, 'build_packages'), '--board',
+      target.name, '--board_root', sysroot.path
+  ]
   cmd += run_configs.GetBuildPackagesArgs()
 
   extra_env = run_configs.GetEnv()
@@ -472,40 +511,41 @@
           str(e), e.result, exception=e, packages=failed_pkgs)
 
 
-def _CreateSysrootSkeleton(sysroot):
+def _CreateSysrootSkeleton(sysroot: sysroot_lib.Sysroot) -> None:
   """Create the sysroot skeleton.
 
   Dependencies: None.
   Creates the sysroot directory structure and installs the portage hooks.
 
   Args:
-    sysroot (sysroot_lib.Sysroot): The sysroot.
+    sysroot: The sysroot.
   """
   sysroot.CreateSkeleton()
 
 
-def _InstallConfigs(sysroot, target):
+def _InstallConfigs(sysroot: sysroot_lib.Sysroot,
+                    target: 'build_target_lib.BuildTarget') -> None:
   """Install standalone configuration files into the sysroot.
 
   Dependencies: The sysroot exists (i.e. CreateSysrootSkeleton).
   Installs the main, board setup, and user make.conf files.
 
   Args:
-    sysroot (sysroot_lib.Sysroot): The sysroot.
-    target (build_target.BuildTarget): The build target being setup in
-      the sysroot.
+    sysroot: The sysroot.
+    target: The build target being setup in the sysroot.
   """
   sysroot.InstallMakeConf()
   sysroot.InstallMakeConfBoardSetup(target.name)
   sysroot.InstallMakeConfUser()
 
 
-def _InstallPortageConfigs(sysroot,
-                           target,
-                           accept_licenses,
-                           local_build,
-                           package_indexes=None,
-                           expanded_binhost_inheritance: bool = False):
+def _InstallPortageConfigs(
+    sysroot: sysroot_lib.Sysroot,
+    target: 'build_target_lib.BuildTarget',
+    accept_licenses: Optional[str],
+    local_build: bool,
+    package_indexes: List['binpkg.PackageIndexInfo'] = None,
+    expanded_binhost_inheritance: bool = False) -> None:
   """Install portage wrappers and configurations.
 
   Dependencies: make.conf.board_setup (InstallConfigs).
@@ -513,13 +553,12 @@
   Refresh the workon symlinks to compensate for crbug.com/679831.
 
   Args:
-    sysroot (sysroot_lib.Sysroot): The sysroot.
-    target (build_target.BuildTarget): The build target being installed
-      in the sysroot.
-    accept_licenses (str): Additional accepted licenses as a string.
-    local_build (bool): If the build is a local only build.
-    package_indexes (list[PackageIndexInfo]): List of information about
-      available prebuilts, youngest first, or None.
+    sysroot: The sysroot.
+    target: The build target being installed in the sysroot.
+    accept_licenses: Additional accepted licenses as a string.
+    local_build: If the build is a local only build.
+    package_indexes: List of information about available prebuilts, youngest
+      first, or None.
     expanded_binhost_inheritance: Whether to allow expanded binhost inheritance.
   """
   sysroot.CreateAllWrappers(friendly_name=target.name)
@@ -533,7 +572,9 @@
       expanded_binhost_inheritance=expanded_binhost_inheritance)
 
 
-def _InstallToolchain(sysroot, target, local_init=True):
+def _InstallToolchain(sysroot: sysroot_lib.Sysroot,
+                      target: 'build_target_lib.BuildTarget',
+                      local_init: bool = True) -> None:
   """Install toolchain and packages.
 
   Dependencies: Portage configs and wrappers have been installed
@@ -541,16 +582,15 @@
   Install the toolchain and the implicit dependencies.
 
   Args:
-    sysroot (sysroot_lib.Sysroot): The sysroot to install to.
-    target (build_target.BuildTarget): The build target whose toolchain is
-      being installed.
-    local_init (bool): Whether to use local packages to bootstrap implicit
+    sysroot: The sysroot to install to.
+    target: The build target whose toolchain is being installed.
+    local_init: Whether to use local packages to bootstrap implicit
       dependencies.
   """
   sysroot.UpdateToolchain(target.name, local_init=local_init)
 
 
-def _RefreshWorkonSymlinks(target, sysroot):
+def _RefreshWorkonSymlinks(target: str, sysroot: sysroot_lib.Sysroot) -> None:
   """Force refresh the workon symlinks.
 
   Create an instance of the WorkonHelper, which will recreate all symlinks
@@ -562,26 +602,27 @@
   instantiated since it refreshes the symlinks in its __init__.
 
   Args:
-    target (str): The build target name.
-    sysroot (sysroot_lib.Sysroot): The board's sysroot.
+    target: The build target name.
+    sysroot: The board's sysroot.
   """
   workon_helper.WorkonHelper(sysroot.path, friendly_name=target)
 
 
-def _ChooseProfile(target, sysroot):
+def _ChooseProfile(target: 'build_target_lib.BuildTarget',
+                   sysroot: sysroot_lib.Sysroot) -> None:
   """Helper function to execute cros_choose_profile.
 
   TODO(saklein) Refactor cros_choose_profile to avoid needing the run
   call here, and by extension this method all together.
 
   Args:
-    target (build_target_lib.BuildTarget): The build target whose profile is
-      being chosen.
-    sysroot (sysroot_lib.Sysroot): The sysroot for which the profile is
-      being chosen.
+    target: The build target whose profile is being chosen.
+    sysroot: The sysroot for which the profile is being chosen.
   """
-  choose_profile = ['cros_choose_profile', '--board', target.name,
-                    '--board-root', sysroot.path]
+  choose_profile = [
+      'cros_choose_profile', '--board', target.name, '--board-root',
+      sysroot.path
+  ]
   if target.profile:
     # Chooses base by default, only override when we have a passed param.
     choose_profile += ['--profile', target.profile]
@@ -594,10 +635,10 @@
     raise e
 
 
-def BundleDebugSymbols(chroot: chroot_lib.Chroot,
+def BundleDebugSymbols(chroot: 'chroot_lib.Chroot',
                        sysroot_class: sysroot_lib.Sysroot,
-                       _build_target: build_target_lib.BuildTarget,
-                       output_dir: str) -> str:
+                       _build_target: 'build_target_lib.BuildTarget',
+                       output_dir: str) -> Optional[str]:
   """Bundle debug symbols into a tarball for importing into GCE.
 
   Bundle the debug symbols found in the sysroot into a .tgz. This assumes
@@ -644,10 +685,10 @@
     return None
 
 
-def BundleBreakpadSymbols(chroot: chroot_lib.Chroot,
+def BundleBreakpadSymbols(chroot: 'chroot_lib.Chroot',
                           sysroot_class: sysroot_lib.Sysroot,
-                          build_target: build_target_lib.BuildTarget,
-                          output_dir: str) -> str:
+                          build_target: 'build_target_lib.BuildTarget',
+                          output_dir: str) -> Optional[str]:
   """Bundle breakpad debug symbols into a tarball for importing into GCE.
 
   Call the GenerateBreakpadSymbols function and archive this into a tar.gz.
@@ -676,8 +717,8 @@
     # materialize and consume all entries so that all are copied to
     # dest dir and complete list of all symbol files is returned.
     sym_file_list = list(
-        GatherSymbolFiles(tempdir=symbol_tmpdir, destdir=dest_tmpdir,
-                          paths=[breakpad_dir]))
+        GatherSymbolFiles(
+            tempdir=symbol_tmpdir, destdir=dest_tmpdir, paths=[breakpad_dir]))
 
     if not sym_file_list:
       logging.warning('No sym files found in %s.', breakpad_dir)
@@ -712,8 +753,8 @@
   source_file_name: str
 
 
-def GenerateBreakpadSymbols(chroot: chroot_lib.Chroot,
-                            build_target: build_target_lib.BuildTarget,
+def GenerateBreakpadSymbols(chroot: 'chroot_lib.Chroot',
+                            build_target: 'build_target_lib.BuildTarget',
                             debug: bool) -> cros_build_lib.CommandResult:
   """Generate breakpad (go/breakpad) symbols for debugging.
 
@@ -730,30 +771,28 @@
   # and that don't help with breakpad debugging (see https://crbug.com/213670).
   exclude_dirs = ['firmware']
 
-  cmd = [
-      'cros_generate_breakpad_symbols'
-  ]
+  cmd = ['cros_generate_breakpad_symbols']
   if debug:
     cmd += ['--debug']
 
   # Execute for board in parallel with half # of cpus available to avoid
   # starving other parallel processes on the same machine.
   cmd += [
-      '--board=%s' % build_target.name,
-      '--jobs', str(max(1, multiprocessing.cpu_count() // 2))
+      '--board=%s' % build_target.name, '--jobs',
+      str(max(1,
+              multiprocessing.cpu_count() // 2))
   ]
   cmd += ['--exclude-dir=%s' % x for x in exclude_dirs]
 
   logging.info('Generating breakpad symbols: %s.', cmd)
   result = cros_build_lib.run(
-      cmd,
-      enter_chroot=True,
-      chroot_args=chroot.get_enter_args())
+      cmd, enter_chroot=True, chroot_args=chroot.get_enter_args())
   return result
 
 
-def GatherSymbolFiles(tempdir:str, destdir:str,
-                      paths: List[str]) -> List[SymbolFileTuple]:
+def GatherSymbolFiles(
+    tempdir: str, destdir: str,
+    paths: List[str]) -> Generator[SymbolFileTuple, None, None]:
   """Locate symbol files in |paths|
 
   This generator function searches all paths for .sym files and copies them to
@@ -781,8 +820,8 @@
   Yields:
     A SymbolFileTuple for every symbol file found in paths.
   """
-  logging.info('GatherSymbolFiles tempdir %s destdir %s paths %s',
-               tempdir, destdir, paths)
+  logging.info('GatherSymbolFiles tempdir %s destdir %s paths %s', tempdir,
+               destdir, paths)
   for p in paths:
     o = urllib.parse.urlparse(p)
     if o.scheme:
@@ -804,8 +843,8 @@
               # path's dirname before copying.
               os.makedirs(os.path.join(destdir, os.path.dirname(relative_path)))
               shutil.copy(filename, os.path.join(destdir, relative_path))
-            yield SymbolFileTuple(relative_path=relative_path,
-                                  source_file_name=filename)
+            yield SymbolFileTuple(
+                relative_path=relative_path, source_file_name=filename)
 
     elif cros_build_lib.IsTarball(p):
       tardir = tempfile.mkdtemp(dir=tempdir)
@@ -836,7 +875,7 @@
       # of the directory.
       if p.endswith('.sym'):
         shutil.copy(p, destdir)
-        yield SymbolFileTuple(relative_path=os.path.basename(p),
-                              source_file_name=p)
+        yield SymbolFileTuple(
+            relative_path=os.path.basename(p), source_file_name=p)
     else:
       raise ValueError('Unexpected input to GatherSymbolFiles: ', p)
diff --git a/service/sysroot_unittest.py b/service/sysroot_unittest.py
index 3ff36c4..3d61166 100644
--- a/service/sysroot_unittest.py
+++ b/service/sysroot_unittest.py
@@ -28,8 +28,8 @@
   def testGetUpdateChrootArgs(self):
     """Test the update chroot args conversion method."""
     # False/0/None tests.
-    instance = sysroot.SetupBoardRunConfig(usepkg=False, jobs=None,
-                                           update_toolchain=False)
+    instance = sysroot.SetupBoardRunConfig(
+        usepkg=False, jobs=None, update_toolchain=False)
     args = instance.GetUpdateChrootArgs()
     self.assertIn('--nousepkg', args)
     self.assertIn('--skip_toolchain_update', args)
@@ -41,8 +41,8 @@
     self.assertNotIn('--jobs', args)
 
     # True/set values tests.
-    instance = sysroot.SetupBoardRunConfig(usepkg=True, jobs=1,
-                                           update_toolchain=True)
+    instance = sysroot.SetupBoardRunConfig(
+        usepkg=True, jobs=1, update_toolchain=True)
     args = instance.GetUpdateChrootArgs()
     self.assertIn('--usepkg', args)
     self.assertIn('--jobs', args)
@@ -63,8 +63,8 @@
     sysroot and install the toolchain by default.
     """
     target_sysroot = sysroot_lib.Sysroot('/build/board')
-    create_mock = self.PatchObject(sysroot, 'Create',
-                                   return_value=target_sysroot)
+    create_mock = self.PatchObject(
+        sysroot, 'Create', return_value=target_sysroot)
     install_toolchain_mock = self.PatchObject(sysroot, 'InstallToolchain')
 
     sysroot.SetupBoard(build_target_lib.BuildTarget('board'))
@@ -75,8 +75,8 @@
   def testRegenConfigs(self):
     """Test the regen configs install prevention."""
     target_sysroot = sysroot_lib.Sysroot('/build/board')
-    create_mock = self.PatchObject(sysroot, 'Create',
-                                   return_value=target_sysroot)
+    create_mock = self.PatchObject(
+        sysroot, 'Create', return_value=target_sysroot)
     install_toolchain_mock = self.PatchObject(sysroot, 'InstallToolchain')
 
     target = build_target_lib.BuildTarget('board')
@@ -183,23 +183,23 @@
     self.chroot = chroot_lib.Chroot(path=self.chroot_path)
     self.build_target = build_target_lib.BuildTarget('target')
 
-
-
   def testCreateSimpleChromeSysroot(self):
     # Mock the artifact copy.
     tar_dest = os.path.join(self.output_dir, constants.CHROME_SYSROOT_TAR)
     self.PatchObject(shutil, 'copy', return_value=tar_dest)
     # Call service, verify arguments passed to run.
-    sysroot.CreateSimpleChromeSysroot(self.chroot, None,
-                                      self.build_target, self.output_dir)
+    sysroot.CreateSimpleChromeSysroot(self.chroot, None, self.build_target,
+                                      self.output_dir)
 
-    self.run_mock.assert_called_with(
-        ['cros_generate_sysroot', '--out-dir', mock.ANY, '--board',
-         self.build_target.name, '--deps-only', '--package',
-         'chromeos-base/chromeos-chrome'], enter_chroot=True,
-         cwd=self.source_root, chroot_args=mock.ANY, extra_env=mock.ANY
-    )
-
+    self.run_mock.assert_called_with([
+        'cros_generate_sysroot', '--out-dir', mock.ANY, '--board',
+        self.build_target.name, '--deps-only', '--package',
+        'chromeos-base/chromeos-chrome'
+    ],
+                                     enter_chroot=True,
+                                     cwd=self.source_root,
+                                     chroot_args=mock.ANY,
+                                     extra_env=mock.ANY)
 
 
 class ArchiveChromeEbuildEnvTest(cros_test_lib.MockTempDirTestCase):
@@ -231,8 +231,8 @@
     self.chrome_v2_dir = os.path.join(chrome_cat_dir, chrome_v2)
 
     # Directory tuple for verifying the result archive contents.
-    self.expected_archive_contents = cros_test_lib.Directory('./',
-                                                             'environment')
+    self.expected_archive_contents = cros_test_lib.Directory(
+        './', 'environment')
 
     # Create a environment.bz2 file to put into folders.
     env_file = os.path.join(self.tempdir, 'environment')
@@ -255,8 +255,8 @@
     """Test a successful single-version run."""
     self._CreateChromeDir(self.chrome_v1_dir)
 
-    created = sysroot.CreateChromeEbuildEnv(
-      self.chroot, self.sysroot, None, self.output_dir)
+    created = sysroot.CreateChromeEbuildEnv(self.chroot, self.sysroot, None,
+                                            self.output_dir)
 
     self.assertStartsWith(created, self.output_dir)
     cros_test_lib.VerifyTarball(created, self.expected_archive_contents)
@@ -268,8 +268,8 @@
     self._CreateChromeDir(self.chrome_v1_dir, populate=False)
     self._CreateChromeDir(self.chrome_v2_dir)
 
-    created = sysroot.CreateChromeEbuildEnv(
-      self.chroot, self.sysroot, None, self.output_dir)
+    created = sysroot.CreateChromeEbuildEnv(self.chroot, self.sysroot, None,
+                                            self.output_dir)
 
     self.assertStartsWith(created, self.output_dir)
     cros_test_lib.VerifyTarball(created, self.expected_archive_contents)
@@ -277,8 +277,8 @@
   def testNoChrome(self):
     """Test no version of chrome present."""
     self.assertIsNone(
-      sysroot.CreateChromeEbuildEnv(self.chroot, self.sysroot, None,
-        self.output_dir))
+        sysroot.CreateChromeEbuildEnv(self.chroot, self.sysroot, None,
+                                      self.output_dir))
 
 
 class GenerateArchiveTest(cros_test_lib.MockTempDirTestCase):
@@ -295,12 +295,12 @@
 
     # Call service, verify arguments passed to run.
     sysroot.GenerateArchive(self.chroot_path, target, pkg_list)
-    self.run_mock.assert_called_with(
-        ['cros_generate_sysroot', '--out-file', constants.TARGET_SYSROOT_TAR,
-         '--out-dir', mock.ANY, '--board', target,
-         '--package', 'virtual/target-fuzzers'],
-        cwd=constants.SOURCE_ROOT
-    )
+    self.run_mock.assert_called_with([
+        'cros_generate_sysroot', '--out-file', constants.TARGET_SYSROOT_TAR,
+        '--out-dir', mock.ANY, '--board', target, '--package',
+        'virtual/target-fuzzers'
+    ],
+                                     cwd=constants.SOURCE_ROOT)
 
 
 class InstallToolchainTest(cros_test_lib.MockTempDirTestCase):
@@ -364,9 +364,8 @@
   def testGetBuildPackagesDefaultArgs(self):
     """Test the build_packages args building for empty/false/0 values."""
     # Test False/None/0 values.
-    instance = sysroot.BuildPackagesRunConfig(usepkg=False,
-                                              install_debug_symbols=False,
-                                              packages=None)
+    instance = sysroot.BuildPackagesRunConfig(
+        usepkg=False, install_debug_symbols=False, packages=None)
 
     args = instance.GetBuildPackagesArgs()
     self.AssertHasRequiredArgs(args)
@@ -412,16 +411,20 @@
     pkg_indexes = [
         binpkg.PackageIndexInfo(
             build_target=build_target_lib.BuildTarget('board'),
-            snapshot_sha='A', location='AAAA'),
+            snapshot_sha='A',
+            location='AAAA'),
         binpkg.PackageIndexInfo(
             build_target=build_target_lib.BuildTarget('board'),
-            snapshot_sha='B', location='BBBB')]
+            snapshot_sha='B',
+            location='BBBB')
+    ]
 
     instance = sysroot.BuildPackagesRunConfig(package_indexes=pkg_indexes)
 
     env = instance.GetEnv()
-    self.assertEqual(env.get('PORTAGE_BINHOST'),
-                     ' '.join([x.location for x in reversed(pkg_indexes)]))
+    self.assertEqual(
+        env.get('PORTAGE_BINHOST'),
+        ' '.join([x.location for x in reversed(pkg_indexes)]))
 
 
 class BuildPackagesTest(cros_test_lib.RunCommandTestCase):
@@ -442,8 +445,10 @@
 
     self.build_packages = os.path.join(constants.CROSUTILS_DIR,
                                        'build_packages')
-    self.base_command = [self.build_packages, '--board', self.board,
-                         '--board_root', self.sysroot_path]
+    self.base_command = [
+        self.build_packages, '--board', self.board, '--board_root',
+        self.sysroot_path
+    ]
 
   def testSuccess(self):
     """Test successful run."""
@@ -459,8 +464,7 @@
     """Test package failure handling."""
     failed = ['cat/pkg', 'foo/bar']
     cpvs = [package_info.SplitCPV(p, strict=False) for p in failed]
-    self.PatchObject(portage_util, 'ParseDieHookStatusFile',
-                     return_value=cpvs)
+    self.PatchObject(portage_util, 'ParseDieHookStatusFile', return_value=cpvs)
 
     config = sysroot.BuildPackagesRunConfig()
     command = self.base_command + config.GetBuildPackagesArgs()
@@ -494,7 +498,6 @@
 STACK CFI 1234
 """
 
-
   def createSymbolFile(self, filename, content=FAT_CONTENT, size=0):
     """Create a symbol file using content with minimum size."""
     osutils.SafeMakedirs(os.path.dirname(filename))
@@ -520,8 +523,8 @@
 
     # Call sysroot.GatherSymbolFiles to find symbol files under self.tempdir
     # and copy them to output_dir.
-    symbol_files = list(sysroot.GatherSymbolFiles(
-        tar_tmp_dir, output_dir, [input_dir]))
+    symbol_files = list(
+        sysroot.GatherSymbolFiles(tar_tmp_dir, output_dir, [input_dir]))
     self.assertEqual(len(symbol_files), 4)
 
   def test_GatherSymbolFiles(self):
@@ -538,8 +541,8 @@
 
     # Call sysroot.GatherSymbolFiles to find symbol files under self.tempdir
     # and copy them to output_dir.
-    symbol_files = list(sysroot.GatherSymbolFiles(
-        tar_tmp_dir, output_dir, [input_dir]))
+    symbol_files = list(
+        sysroot.GatherSymbolFiles(tar_tmp_dir, output_dir, [input_dir]))
 
     # Construct the expected symbol files. Note that the SymbolFileTuple
     # field source_file_name is the full path to where a symbol file was found,
@@ -563,8 +566,8 @@
     # Sort symbol_files and expected_output_files by the relative_path
     # attribute.
     symbol_files = sorted(symbol_files, key=attrgetter('relative_path'))
-    expected_symbol_files = sorted(expected_symbol_files,
-                                   key=attrgetter('relative_path'))
+    expected_symbol_files = sorted(
+        expected_symbol_files, key=attrgetter('relative_path'))
     # Compare the files to the expected files. This verifies the size and
     # contents, and on failure shows the full contents.
     self.assertEqual(symbol_files, expected_symbol_files)
@@ -590,8 +593,10 @@
 
     # Set up test input directory.
     tarball_dir = os.path.join(self.tempdir, 'some/path')
-    files_in_tarball = ['dir1/fileZ.sym', 'dir2/fileY.sym', 'dir2/fileX.sym',
-                        'fileA.sym', 'fileB.sym', 'fileC.sym']
+    files_in_tarball = [
+        'dir1/fileZ.sym', 'dir2/fileY.sym', 'dir2/fileX.sym', 'fileA.sym',
+        'fileB.sym', 'fileC.sym'
+    ]
     for filename in files_in_tarball:
       self.createSymbolFile(os.path.join(tarball_dir, filename))
     temp_tarball_file_path = os.path.join(self.tempdir, 'symfiles.tar')
@@ -604,18 +609,17 @@
     shutil.move(temp_tarball_file_path, tarball_path)
 
     # Execute sysroot.GatherSymbolFiles where the path contains the tarball.
-    symbol_files = list(sysroot.GatherSymbolFiles(
-        tarball_dir, output_dir, [tarball_path]))
+    symbol_files = list(
+        sysroot.GatherSymbolFiles(tarball_dir, output_dir, [tarball_path]))
 
     self.assertEqual(len(symbol_files), 6)
     # Verify the symbol_file relative_paths.
-    symbol_file_relative_paths = [
-        obj.relative_path for obj in symbol_files
-    ]
+    symbol_file_relative_paths = [obj.relative_path for obj in symbol_files]
     symbol_file_relative_paths.sort()
-    self.assertEqual(symbol_file_relative_paths,
-                     ['dir1/fileZ.sym', 'dir2/fileX.sym', 'dir2/fileY.sym',
-                      'fileA.sym', 'fileB.sym', 'fileC.sym'])
+    self.assertEqual(symbol_file_relative_paths, [
+        'dir1/fileZ.sym', 'dir2/fileX.sym', 'dir2/fileY.sym', 'fileA.sym',
+        'fileB.sym', 'fileC.sym'
+    ])
     # Verify the symbol_file source_file_names.
     symbol_file_source_file_names = [
         obj.source_file_name for obj in symbol_files
@@ -655,8 +659,9 @@
 
     # Set up test input directory.
     tarball_dir = os.path.join(self.tempdir, 'some/path')
-    files_in_tarball = ['dir1/fileU.sym', 'dir1/fileU.txt',
-                        'fileD.sym', 'fileD.txt']
+    files_in_tarball = [
+        'dir1/fileU.sym', 'dir1/fileU.txt', 'fileD.sym', 'fileD.txt'
+    ]
     for filename in files_in_tarball:
       # we don't care about file contents, so we are using createSymbolFile
       # for files whether they end with .sym or not.
@@ -671,13 +676,11 @@
     shutil.move(temp_tarball_file_path, tarball_path)
 
     # Execute sysroot.GatherSymbolFiles where the path contains the tarball.
-    symbol_files = list(sysroot.GatherSymbolFiles(
-        tarball_dir, output_dir, [tarball_path]))
+    symbol_files = list(
+        sysroot.GatherSymbolFiles(tarball_dir, output_dir, [tarball_path]))
 
     # Verify the symbol_file relative_paths only has .sym files.
-    symbol_file_relative_paths = [
-        obj.relative_path for obj in symbol_files
-    ]
+    symbol_file_relative_paths = [obj.relative_path for obj in symbol_files]
     symbol_file_relative_paths.sort()
     self.assertEqual(symbol_file_relative_paths,
                      ['dir1/fileU.sym', 'fileD.sym'])
@@ -697,10 +700,11 @@
 
     # Call sysroot.GatherSymbolFiles with full paths to files, some of which
     # don't end in .sym, verify that only .sym files get copied to output_dir.
-    symbol_files = list(sysroot.GatherSymbolFiles(
-        tar_tmp_dir, output_dir,
-        [os.path.join(input_dir, 'a_file.sym'),
-         os.path.join(input_dir, 'a_file.txt')]))
+    symbol_files = list(
+        sysroot.GatherSymbolFiles(tar_tmp_dir, output_dir, [
+            os.path.join(input_dir, 'a_file.sym'),
+            os.path.join(input_dir, 'a_file.txt')
+        ]))
 
     # Construct the expected symbol files. Note that the SymbolFileTuple
     # field source_file_name is the full path to where a symbol file was found,
@@ -746,10 +750,10 @@
     # Call the method being tested.
     sysroot.GenerateBreakpadSymbols(chroot, build_target, False)
 
-    cros_build_lib.run.assert_called_with(['cros_generate_breakpad_symbols',
-                                           '--board=board',
-                                           '--jobs', mock.ANY,
-                                           '--exclude-dir=firmware'],
+    cros_build_lib.run.assert_called_with([
+        'cros_generate_breakpad_symbols', '--board=board', '--jobs', mock.ANY,
+        '--exclude-dir=firmware'
+    ],
                                           enter_chroot=True,
                                           chroot_args=['--chroot', mock.ANY])
 
@@ -762,11 +766,10 @@
     # Call the method being tested.
     sysroot.GenerateBreakpadSymbols(chroot, build_target, True)
 
-    cros_build_lib.run.assert_called_with(['cros_generate_breakpad_symbols',
-                                           '--debug',
-                                           '--board=board',
-                                           '--jobs', mock.ANY,
-                                           '--exclude-dir=firmware'],
+    cros_build_lib.run.assert_called_with([
+        'cros_generate_breakpad_symbols', '--debug', '--board=board', '--jobs',
+        mock.ANY, '--exclude-dir=firmware'
+    ],
                                           enter_chroot=True,
                                           chroot_args=['--chroot', mock.ANY])
 
@@ -785,7 +788,6 @@
     osutils.SafeMakedirs(self.sysroot_path)
     osutils.SafeMakedirs(os.path.join(self.chroot_path, 'tmp'))
 
-
     # Create output dir.
     self.output_dir = os.path.join(self.tempdir, 'output_dir')
     osutils.SafeMakedirs(self.output_dir)
@@ -799,13 +801,17 @@
     """BundleBreakpadSymbols calls cbuildbot/commands with correct args."""
     # Patch service layer functions.
     generate_breakpad_symbols_patch = self.PatchObject(
-        sysroot, 'GenerateBreakpadSymbols',
+        sysroot,
+        'GenerateBreakpadSymbols',
         return_value=cros_build_lib.CommandResult(returncode=0, output=''))
     gather_symbol_files_patch = self.PatchObject(
-        sysroot, 'GatherSymbolFiles',
-        return_value=[sysroot.SymbolFileTuple(
-            source_file_name='path/to/source/file1.sym',
-            relative_path='file1.sym')])
+        sysroot,
+        'GatherSymbolFiles',
+        return_value=[
+            sysroot.SymbolFileTuple(
+                source_file_name='path/to/source/file1.sym',
+                relative_path='file1.sym')
+        ])
 
     tar_file = sysroot.BundleBreakpadSymbols(self.chroot, self.sysroot,
                                              self.build_target, self.output_dir)
@@ -825,11 +831,12 @@
     self.PatchObject(os.path, 'isdir', return_value=True)
 
     create_tarball_patch = self.PatchObject(
-        cros_build_lib, 'CreateTarball',
+        cros_build_lib,
+        'CreateTarball',
         return_value=cros_build_lib.CommandResult(returncode=0, output=''))
 
-    tar_file = sysroot.BundleDebugSymbols(self.chroot, self.sysroot,
-                                          None, self.output_dir)
+    tar_file = sysroot.BundleDebugSymbols(self.chroot, self.sysroot, None,
+                                          self.output_dir)
     create_tarball_patch.assert_called()
 
     # Verify response contents.
diff --git a/service/test.py b/service/test.py
index 8cad931..2af30a3 100644
--- a/service/test.py
+++ b/service/test.py
@@ -15,7 +15,6 @@
 
 from chromite.cbuildbot import commands
 from chromite.lib import autotest_util
-from chromite.lib import chroot_lib
 from chromite.lib import constants
 from chromite.lib import cros_build_lib
 from chromite.lib import failures_lib
@@ -23,10 +22,13 @@
 from chromite.lib import moblab_vm
 from chromite.lib import osutils
 from chromite.lib import portage_util
-from chromite.lib import sysroot_lib
 from chromite.utils import code_coverage_util
 
 if TYPE_CHECKING:
+  from chromite.cbuildbot import goma_util
+  from chromite.lib import build_target_lib
+  from chromite.lib import chroot_lib
+  from chromite.lib import sysroot_lib
   from chromite.lib.parser import package_info
 
 
@@ -57,35 +59,40 @@
     return self.return_code == 0 and len(self.failed_pkgs) == 0
 
 
-def BuildTargetUnitTest(build_target,
-                        chroot,
-                        packages=None,
-                        blocklist=None,
-                        was_built=True,
-                        code_coverage=False,
-                        testable_packages_optional=False,
-                        filter_only_cros_workon: bool = False):
+def BuildTargetUnitTest(
+    build_target: 'build_target_lib.BuildTarget',
+    chroot: 'chroot_lib.Chroot',
+    packages: Optional[List[str]] = None,
+    blocklist: Optional[List[str]] = None,
+    was_built: bool = True,
+    code_coverage: bool = False,
+    testable_packages_optional: bool = False,
+    filter_only_cros_workon: bool = False) -> BuildTargetUnitTestResult:
   """Run the ebuild unit tests for the target.
 
   Args:
-    build_target (build_target_lib.BuildTarget): The build target.
-    chroot (chroot_lib.Chroot): The chroot where the tests are running.
-    packages (list[str]|None): Packages to be tested. If none, uses all testable
-      packages.
-    blocklist (list[str]|None): Tests to skip.
-    was_built (bool): Whether packages were built.
-    code_coverage (bool): Whether to produce code coverage data.
-    testable_packages_optional (bool): Whether to allow no testable packages to
-      be found.
-    filter_only_cros_workon (bool): Whether to filter out non-cros_workon
-      packages from input package list.
+    build_target: The build target.
+    chroot: The chroot where the tests are running.
+    packages: Packages to be tested. If none, uses all testable packages.
+    blocklist: Tests to skip.
+    was_built: Whether packages were built.
+    code_coverage: Whether to produce code coverage data.
+    testable_packages_optional: Whether to allow no testable packages to be
+      found.
+    filter_only_cros_workon: Whether to filter out non-cros_workon packages from
+      input package list.
 
   Returns:
     BuildTargetUnitTestResult
   """
   # TODO(saklein) Refactor commands.RunUnitTests to use this/the API.
   # TODO(crbug.com/960805) Move cros_run_unit_tests logic here.
-  cmd = ['cros_run_unit_tests', '--board', build_target.name]
+  cmd = ['cros_run_unit_tests']
+
+  if build_target.is_host():
+    cmd.extend(['--host'])
+  else:
+    cmd.extend(['--board', build_target.name])
 
   if packages:
     cmd.extend(['--packages', ' '.join(packages)])
@@ -126,13 +133,18 @@
   return BuildTargetUnitTestResult(result.returncode, failed_pkgs)
 
 
-def BuildTargetUnitTestTarball(chroot, sysroot, result_path):
+def BuildTargetUnitTestTarball(chroot: 'chroot_lib.Chroot',
+                               sysroot: 'sysroot_lib.Sysroot',
+                               result_path: str) -> Optional[str]:
   """Build the unittest tarball.
 
   Args:
-    chroot (chroot_lib.Chroot): Chroot where the tests were run.
-    sysroot (sysroot_lib.Sysroot): The sysroot where the tests were run.
-    result_path (str): The directory where the archive should be created.
+    chroot: Chroot where the tests were run.
+    sysroot: The sysroot where the tests were run.
+    result_path: The directory where the archive should be created.
+
+  Returns:
+    The tarball path or None.
   """
   tarball = 'unit_tests.tar'
   tarball_path = os.path.join(result_path, tarball)
@@ -152,15 +164,17 @@
   return tarball_path if result.returncode == 0 else None
 
 
-def BundleHwqualTarball(board, version, chroot, sysroot, result_path):
+def BundleHwqualTarball(board: str, version: str, chroot: 'chroot_lib.Chroot',
+                        sysroot: 'sysroot_lib.Sysroot',
+                        result_path: str) -> Optional[str]:
   """Build the hwqual tarball.
 
   Args:
-    board (str): The board name.
-    version (str): The version string to use for the image.
-    chroot (chroot_lib.Chroot): Chroot where the tests were run.
-    sysroot (sysroot_lib.Sysroot): The sysroot where the tests were run.
-    result_path (str): The directory where the archive should be created.
+    board: The board name.
+    version: The version string to use for the image.
+    chroot: Chroot where the tests were run.
+    sysroot: The sysroot where the tests were run.
+    result_path: The directory where the archive should be created.
 
   Returns:
     The output path or None.
@@ -204,14 +218,14 @@
   return artifact_path
 
 
-def DebugInfoTest(sysroot_path):
+def DebugInfoTest(sysroot_path: str) -> bool:
   """Run the debug info tests.
 
   Args:
-    sysroot_path (str): The sysroot being tested.
+    sysroot_path: The sysroot being tested.
 
   Returns:
-    bool: True iff all tests passed, False otherwise.
+    True iff all tests passed, False otherwise.
   """
   cmd = ['debug_info_test', os.path.join(sysroot_path, 'usr/lib/debug')]
   result = cros_build_lib.run(cmd, enter_chroot=True, check=False)
@@ -219,11 +233,11 @@
   return result.returncode == 0
 
 
-def ChromiteUnitTest():
+def ChromiteUnitTest() -> bool:
   """Run chromite unittests.
 
   Returns:
-    bool: True iff all tests passed, False otherwise.
+    True iff all tests passed, False otherwise.
   """
   cmd = [
       os.path.join(constants.CHROMITE_DIR, 'run_tests'),
@@ -233,35 +247,37 @@
   return result.returncode == 0
 
 
-def CreateMoblabVm(workspace_dir, chroot_dir, image_dir):
+def CreateMoblabVm(workspace_dir: str, chroot_dir: str,
+                   image_dir: str) -> moblab_vm.MoblabVm:
   """Create the moblab VMs.
 
   Assumes that image_dir is in exactly the state it was after building
   a test image and then converting it to a VM image.
 
   Args:
-    workspace_dir (str): Workspace for the moblab VM.
-    chroot_dir (str): Directory containing the chroot for the moblab VM.
-    image_dir (str): Directory containing the VM image.
+    workspace_dir: Workspace for the moblab VM.
+    chroot_dir: Directory containing the chroot for the moblab VM.
+    image_dir: Directory containing the VM image.
 
   Returns:
-    MoblabVm: The resulting VM.
+    The resulting VM.
   """
   vms = moblab_vm.MoblabVm(workspace_dir, chroot_dir=chroot_dir)
   vms.Create(image_dir, dut_image_dir=image_dir, create_vm_images=False)
   return vms
 
 
-def PrepareMoblabVmImageCache(vms, builder, payload_dirs):
+def PrepareMoblabVmImageCache(vms: moblab_vm.MoblabVm, builder: str,
+                              payload_dirs: List[str]) -> str:
   """Preload the given payloads into the moblab VM image cache.
 
   Args:
-    vms (MoblabVm): The Moblab VM.
-    builder (str): The builder path, used to name the cache dir.
-    payload_dirs (list[str]): List of payload directories to load.
+    vms: The Moblab VM.
+    builder: The builder path, used to name the cache dir.
+    payload_dirs: List of payload directories to load.
 
   Returns:
-    str: Absolute path to the image cache path.
+    Absolute path to the image cache path.
   """
   with vms.MountedMoblabDiskContext() as disk_dir:
     image_cache_root = os.path.join(disk_dir, 'static/prefetched')
@@ -278,15 +294,17 @@
   return os.path.join('/', 'mnt/moblab', image_cache_rel_dir)
 
 
-def RunMoblabVmTest(chroot, vms, builder, image_cache_dir, results_dir):
+def RunMoblabVmTest(chroot: 'chroot_lib.Chroot', vms: moblab_vm.MoblabVm,
+                    builder: str, image_cache_dir: str,
+                    results_dir: str) -> None:
   """Run Moblab VM tests.
 
   Args:
-    chroot (chroot_lib.Chroot): The chroot in which to run tests.
-    builder (str): The builder path, used to find artifacts on GS.
-    vms (MoblabVm): The Moblab VMs to test.
-    image_cache_dir (str): Path to artifacts cache.
-    results_dir (str): Path to output test results.
+    chroot: The chroot in which to run tests.
+    builder: The builder path, used to find artifacts on GS.
+    vms: The Moblab VMs to test.
+    image_cache_dir: Path to artifacts cache.
+    results_dir: Path to output test results.
   """
   with vms.RunVmsContext():
     # TODO(evanhernandez): Move many of these arguments to test config.
@@ -317,15 +335,16 @@
     )
 
 
-def SimpleChromeWorkflowTest(sysroot_path, build_target_name, chrome_root,
-                             goma):
+def SimpleChromeWorkflowTest(sysroot_path: str, build_target_name: str,
+                             chrome_root: str,
+                             goma: Optional['goma_util.Goma']) -> None:
   """Execute SimpleChrome workflow tests
 
   Args:
-    sysroot_path (str): The sysroot path for testing Chrome.
-    build_target_name (str): Board build target
-    chrome_root (str): Path to Chrome source root.
-    goma (goma_util.Goma): Goma object (or None).
+    sysroot_path: The sysroot path for testing Chrome.
+    build_target_name: Board build target
+    chrome_root: Path to Chrome source root.
+    goma: Goma object or None.
   """
   board_dir = 'out_%s' % build_target_name
 
@@ -345,16 +364,17 @@
     _VMTestChrome(build_target_name, sdk_cmd)
 
 
-def _InitSimpleChromeSDK(tempdir, build_target_name, sysroot_path, chrome_root,
-                         use_goma):
+def _InitSimpleChromeSDK(tempdir: str, build_target_name: str,
+                         sysroot_path: str, chrome_root: str,
+                         use_goma: bool) -> commands.ChromeSDK:
   """Create ChromeSDK object for executing 'cros chrome-sdk' commands.
 
   Args:
-    tempdir (string): Tempdir for command execution.
-    build_target_name (string): Board build target.
-    sysroot_path (string): Sysroot for Chrome to use.
-    chrome_root (string): Path to Chrome.
-    use_goma (bool): Whether to use goma.
+    tempdir: Tempdir for command execution.
+    build_target_name: Board build target.
+    sysroot_path: Sysroot for Chrome to use.
+    chrome_root: Path to Chrome.
+    use_goma: Whether to use goma.
 
   Returns:
     A ChromeSDK object.
@@ -372,11 +392,11 @@
   return sdk_cmd
 
 
-def _VerifySDKEnvironment(out_board_dir):
+def _VerifySDKEnvironment(out_board_dir: str) -> None:
   """Make sure the SDK environment is set up properly.
 
   Args:
-    out_board_dir (str): Output SDK dir for board.
+    out_board_dir: Output SDK dir for board.
   """
   if not os.path.exists(out_board_dir):
     raise AssertionError('%s not created!' % out_board_dir)
@@ -384,14 +404,15 @@
                osutils.ReadFile(os.path.join(out_board_dir, 'args.gn')))
 
 
-def _BuildChrome(sdk_cmd, chrome_root, out_board_dir, goma):
+def _BuildChrome(sdk_cmd: commands.ChromeSDK, chrome_root: str,
+                 out_board_dir: str, goma: Optional['goma_util.Goma']) -> None:
   """Build Chrome with SimpleChrome environment.
 
   Args:
-    sdk_cmd (ChromeSDK object): sdk_cmd to run cros chrome-sdk commands.
-    chrome_root (string): Path to Chrome.
-    out_board_dir (string): Path to board directory.
-    goma (goma_util.Goma): Goma object
+    sdk_cmd: sdk_cmd to run cros chrome-sdk commands.
+    chrome_root: Path to Chrome.
+    out_board_dir: Path to board directory.
+    goma: Goma object or None
   """
   # Validate fetching of the SDK and setting everything up.
   sdk_cmd.Run(['true'])
@@ -443,12 +464,12 @@
             str(result.returncode))
 
 
-def _TestDeployChrome(sdk_cmd, out_board_dir):
+def _TestDeployChrome(sdk_cmd: commands.ChromeSDK, out_board_dir: str) -> None:
   """Test SDK deployment.
 
   Args:
-    sdk_cmd (ChromeSDK object): sdk_cmd to run cros chrome-sdk commands.
-    out_board_dir (string): Path to board directory.
+    sdk_cmd: sdk_cmd to run cros chrome-sdk commands.
+    out_board_dir: Path to board directory.
   """
   with osutils.TempDir(prefix='chrome-sdk-stage') as tempdir:
     # Use the TOT deploy_chrome.
@@ -465,8 +486,13 @@
           'deploy_chrome did not run successfully! Searched %s' % (chromepath))
 
 
-def _VMTestChrome(board, sdk_cmd):
-  """Run cros_run_test."""
+def _VMTestChrome(board: str, sdk_cmd: commands.ChromeSDK) -> None:
+  """Run cros_run_test.
+
+  Args:
+    board: The name of the board.
+    sdk_cmd: sdk_cmd to run cros chrome-sdk commands.
+  """
   image_dir_symlink = image_lib.GetLatestImageLink(board)
   image_path = os.path.join(image_dir_symlink, constants.VM_IMAGE_BIN)
 
@@ -475,11 +501,11 @@
     sdk_cmd.VMTest(image_path)
 
 
-def ValidateMoblabVmTest(results_dir):
+def ValidateMoblabVmTest(results_dir: str) -> None:
   """Determine if the VM test passed or not.
 
   Args:
-    results_dir (str): Path to directory containing test_that results.
+    results_dir: Path to directory containing test_that results.
 
   Raises:
     failures_lib.TestFailure: If dummy_PassServer did not run or failed.
@@ -494,16 +520,15 @@
                                    'not successfully run dummy_PassServer.')
 
 
-def BundleCodeCoverageLlvmJson(chroot: chroot_lib.Chroot,
-                               sysroot_class: sysroot_lib.Sysroot,
-                               output_dir: str):
+def BundleCodeCoverageLlvmJson(chroot: 'chroot_lib.Chroot',
+                               sysroot_class: 'sysroot_lib.Sysroot',
+                               output_dir: str) -> Optional[str]:
   """Bundle code coverage llvm json into a tarball for importing into GCE.
 
   Args:
     chroot: The chroot class used for these artifacts.
     sysroot_class: The sysroot class used for these artifacts.
     output_dir: The path to write artifacts to.
-    build_target_name: The build target
 
   Returns:
     A string path to the output code_coverage.tar.xz artifact, or None.
@@ -540,7 +565,8 @@
 def GatherCodeCoverageLlvmJsonFile(
     destdir: str,
     paths: List[str],
-    output_file_name='coverage.json') -> GatherCodeCoverageLlvmJsonFileResult:
+    output_file_name: str = 'coverage.json'
+) -> GatherCodeCoverageLlvmJsonFileResult:
   """Locate code coverage llvm json files in |paths|.
 
    This function locates all the coverage llvm json files and merges them
@@ -605,8 +631,8 @@
       joined_file_paths=joined_file_paths)
 
 
-def FindAllMetadataFiles(chroot: chroot_lib.Chroot,
-                         sysroot: sysroot_lib.Sysroot) -> List[str]:
+def FindAllMetadataFiles(chroot: 'chroot_lib.Chroot',
+                         sysroot: 'sysroot_lib.Sysroot') -> List[str]:
   """Find the full paths to all test metadata paths."""
   # Right now there's no use case for this function inside the chroot.
   # If it's useful, we could make the chroot param optional to run in the SDK.
@@ -619,8 +645,8 @@
   ]
 
 
-def _FindAutotestMetadataFile(chroot: chroot_lib.Chroot,
-                              sysroot: sysroot_lib.Sysroot) -> str:
+def _FindAutotestMetadataFile(chroot: 'chroot_lib.Chroot',
+                              sysroot: 'sysroot_lib.Sysroot') -> str:
   """Find the full path to the Autotest test metadata file.
 
   This file is installed during the chromeos-base/autotest ebuild.
@@ -629,8 +655,8 @@
       sysroot.Path('usr', 'local', 'build', 'autotest', 'autotest_metadata.pb'))
 
 
-def _FindTastLocalMetadataFile(chroot: chroot_lib.Chroot,
-                               sysroot: sysroot_lib.Sysroot) -> str:
+def _FindTastLocalMetadataFile(chroot: 'chroot_lib.Chroot',
+                               sysroot: 'sysroot_lib.Sysroot') -> str:
   """Find the full path to the Tast local test metadata file.
 
   This file is installed during the tast-bundle eclass.
@@ -639,8 +665,8 @@
       sysroot.Path('usr', 'share', 'tast', 'metadata', 'local', 'cros.pb'))
 
 
-def _FindTastLocalPrivateMetadataFile(chroot: chroot_lib.Chroot,
-                                      sysroot: sysroot_lib.Sysroot) -> str:
+def _FindTastLocalPrivateMetadataFile(chroot: 'chroot_lib.Chroot',
+                                      sysroot: 'sysroot_lib.Sysroot') -> str:
   """Find the full path to the Tast local private test metadata file.
 
   This file is installed during the tast-bundle eclass.
@@ -649,7 +675,7 @@
       sysroot.Path('build', 'share', 'tast', 'metadata', 'local', 'crosint.pb'))
 
 
-def _FindTastRemoteMetadataFile(chroot: chroot_lib.Chroot) -> str:
+def _FindTastRemoteMetadataFile(chroot: 'chroot_lib.Chroot') -> str:
   """Find the full path to the Tast remote test metadata file.
 
   This file is installed during the tast-bundle eclass.
diff --git a/service/test_unittest.py b/service/test_unittest.py
index 96316b8..a259b04 100644
--- a/service/test_unittest.py
+++ b/service/test_unittest.py
@@ -86,6 +86,14 @@
     self.assertCommandContains(['cros_run_unit_tests', '--board', self.board])
     self.assertTrue(result.success)
 
+  def testHost(self):
+    """Test host target."""
+    host_build_target = build_target_lib.BuildTarget('')
+    result = test.BuildTargetUnitTest(host_build_target, self.chroot)
+
+    self.assertCommandContains(['cros_run_unit_tests', '--host'])
+    self.assertTrue(result.success)
+
   def testPackages(self):
     """Test the packages argument."""
     packages = ['foo/bar', 'cat/pkg']
@@ -215,14 +223,14 @@
 class MoblabVmTestCase(cros_test_lib.RunCommandTempDirTestCase):
   """Tests for the SetupBoardRunConfig class."""
 
-  def MockDirectory(self, path):
+  def MockDirectory(self, path: str) -> str:
     """Create an empty directory.
 
     Args:
-      path (str): Relative path for the directory.
+      path: Relative path for the directory.
 
     Returns:
-      str: Path to the directory.
+      Path to the directory.
     """
     path = os.path.join(self.tempdir, path)
     osutils.SafeMakedirs(path)
diff --git a/signing/bin/sign_image.py b/signing/bin/sign_image.py
index ec2cdbf..fcb9fbd 100644
--- a/signing/bin/sign_image.py
+++ b/signing/bin/sign_image.py
@@ -37,7 +37,7 @@
 ValidImageTypes = (
     'ssd', 'base', 'usb', 'recovery', 'factory', 'install', 'firmware',
     'kernel', 'recovery_kernel', 'update_payload',
-    'accessory_usbpd', 'accessory_rwsig',
+    'accessory_usbpd', 'accessory_rwsig', 'hps_firmware',
 )
 
 
@@ -65,6 +65,6 @@
 
   # TODO(lamontjones): implement signing for the other supported image types:
   # firmware, kernel, recovery_kernel, update_payload,
-  # accessory_usbpd, accessory_rwsig.
+  # accessory_usbpd, accessory_rwsig, hps_firmware.
   logging.error('Unimplemented --type %s', options.image_type)
   return 2
diff --git a/signing/image_signing/imagefile.py b/signing/image_signing/imagefile.py
index 6c66c5f..e2b14f1 100644
--- a/signing/image_signing/imagefile.py
+++ b/signing/image_signing/imagefile.py
@@ -265,12 +265,13 @@
            'hashtree=%s' % self._file.name]
     if salt:
       cmd.append('salt=%s' % salt.value)
-    verity = cros_build_lib.sudo_run(
+    target_template = cros_build_lib.sudo_run(
         cmd, print_cmd=False, capture_output=True, encoding='utf-8').stdout
-    # verity is a templated DmLine string.
-    slave = kernel_cmdline.DmLine(
-        verity.replace('ROOT_DEV', root_dev).replace('HASH_DEV', hash_dev))
-    vroot_dev.rows[0] = slave
+    # target_template is a templated DmLine string.
+    target = kernel_cmdline.DmLine(
+        target_template.replace('ROOT_DEV', root_dev).replace(
+            'HASH_DEV', hash_dev))
+    vroot_dev.rows[0] = target
     self.calculated_dm_config = dm_config
     self.calculated_kernel_cmdline = self.cmd_line
     self.hashtree_filename = self._file.name
diff --git a/signing/lib/firmware.py b/signing/lib/firmware.py
index 928964a..6b88b5e 100644
--- a/signing/lib/firmware.py
+++ b/signing/lib/firmware.py
@@ -167,7 +167,7 @@
     """Perform one signing based on the given args.
 
     Args:
-      keyset: master keyset used for signing,
+      keyset: keyset directory used for signing,
       shellball_dir: location of extracted shellball
       bios_image: relitive path of bios.bin in shellball
       ec_image: relative path of ec.bin in shellball
@@ -210,7 +210,7 @@
     are signed. Else all bios*.bin in shellball will be signed.
 
     Args:
-      keyset: master keyset, with subkeys[key_id] if defined
+      keyset: keyset directory, with subkeys[key_id] if defined
       input_name: location of extracted shellball
       output_name: unused
 
diff --git a/signing/signer_instructions/README.md b/signing/signer_instructions/README.md
index 2ede6cc..90dd8cf 100644
--- a/signing/signer_instructions/README.md
+++ b/signing/signer_instructions/README.md
@@ -99,7 +99,6 @@
 
 ## References
 
-For details on the fields that the signer uses:
-http://go/cros-sites-archive/resources/engineering/releng/signer-documentation
+For details on the fields that the signer uses: http://go/cros-signer-docs.
 
 [pushimage]: /scripts/pushimage.py
diff --git a/test/portage_fixtures.py b/test/portage_fixtures.py
index 1747b75..73d9b22 100644
--- a/test/portage_fixtures.py
+++ b/test/portage_fixtures.py
@@ -19,7 +19,7 @@
   """Factory for stacked Portage overlays.
 
   The factory function takes an integer argument and returns an iterator of
-  that many overlays, each of which has all prior overlays as masters.
+  that many overlays, each of which has all prior overlays as parents.
   """
 
   def make_overlay_stack(height):
@@ -36,7 +36,7 @@
               root_path=tmp_path_factory.mktemp(
                   'overlay-' + cr.test.Overlay.HIERARCHY_NAMES[i]),
               name=cr.test.Overlay.HIERARCHY_NAMES[i],
-              masters=overlays))
+              parent_overlays=overlays))
       yield overlays[i]
 
   return make_overlay_stack
diff --git a/test/portage_testables.py b/test/portage_testables.py
index e6c19c9..047f2d6 100644
--- a/test/portage_testables.py
+++ b/test/portage_testables.py
@@ -47,10 +47,10 @@
   HIERARCHY_NAMES = ('stable', 'project', 'chipset', 'baseboard', 'board',
                      'board-private')
 
-  def __init__(self, root_path, name, masters=None):
+  def __init__(self, root_path, name, parent_overlays=None):
     self.path = pathlib.Path(root_path)
     self.name = str(name)
-    self.masters = tuple(masters) if masters else None
+    self.parent_overlays = tuple(parent_overlays) if parent_overlays else None
     self.packages = []
     self.profiles = dict()
     self.categories = set()
@@ -73,9 +73,9 @@
   def _write_layout_conf(self):
     """Write out the layout.conf as part of this Overlay's initialization."""
     layout_conf_path = self.path / 'metadata' / 'layout.conf'
-    master_names = ' '.join(m.name for m in self.masters or [])
+    parent_names = ' '.join(m.name for m in self.parent_overlays or [])
     conf = {
-        'masters': 'portage-stable chromiumos eclass-overlay' + master_names,
+        'masters': 'portage-stable chromiumos eclass-overlay' + parent_names,
         'profile-formats': 'portage-2 profile-default-eapi',
         'profile_eapi_when_unspecified': '5-progress',
         'repo-name': str(self.name),
diff --git a/test/portage_testables_unittest.py b/test/portage_testables_unittest.py
index 6e417ca..9cbdd48 100644
--- a/test/portage_testables_unittest.py
+++ b/test/portage_testables_unittest.py
@@ -16,14 +16,14 @@
 
 
 @pytest.mark.parametrize('height', _OVERLAY_STACK_PARAMS)
-def test_overlay_stack_masters(height, overlay_stack):
-  """Test that overlays have the correct masters set."""
+def test_overlay_stack_parents(height, overlay_stack):
+  """Test that overlays have the correct parents set."""
   overlays = list(overlay_stack(height))
 
-  assert overlays[0].masters is None
+  assert overlays[0].parent_overlays is None
 
   for x in range(1, height):
-    assert overlays[x].masters == tuple(overlays[:x])
+    assert overlays[x].parent_overlays == tuple(overlays[:x])
 
 
 @pytest.mark.parametrize('height', _OVERLAY_STACK_PARAMS)
diff --git a/third_party/lddtree.py b/third_party/lddtree.py
index a3629da..041931b 100644
--- a/third_party/lddtree.py
+++ b/third_party/lddtree.py
@@ -382,7 +382,11 @@
   dbg(debug, 'ParseELF(%s)' % path)
 
   with open(path, 'rb') as f:
-    elf = ELFFile(f)
+    try:
+      elf = ELFFile(f)
+    except exceptions.ELFParseError:
+      warn('ELFParser failed to parse %s' % (path,))
+      raise
 
     # If this is the first ELF, extract the interpreter.
     if _first:
diff --git a/third_party/pylint-quotes/LICENSE b/third_party/pylint_quotes/LICENSE
similarity index 100%
rename from third_party/pylint-quotes/LICENSE
rename to third_party/pylint_quotes/LICENSE
diff --git a/third_party/pylint-quotes/pylint_quotes/__init__.py b/third_party/pylint_quotes/__init__.py
similarity index 100%
rename from third_party/pylint-quotes/pylint_quotes/__init__.py
rename to third_party/pylint_quotes/__init__.py
diff --git a/third_party/pylint-quotes/pylint_quotes/__version__.py b/third_party/pylint_quotes/__version__.py
similarity index 100%
rename from third_party/pylint-quotes/pylint_quotes/__version__.py
rename to third_party/pylint_quotes/__version__.py
diff --git a/third_party/pylint-quotes/pylint_quotes/checker.py b/third_party/pylint_quotes/checker.py
similarity index 100%
rename from third_party/pylint-quotes/pylint_quotes/checker.py
rename to third_party/pylint_quotes/checker.py
diff --git a/third_party/pylint-quotes/pylint_quotes/plugin.py b/third_party/pylint_quotes/plugin.py
similarity index 100%
rename from third_party/pylint-quotes/pylint_quotes/plugin.py
rename to third_party/pylint_quotes/plugin.py
diff --git a/utils/timer.py b/utils/timer.py
index bf359a1..22e2a43 100644
--- a/utils/timer.py
+++ b/utils/timer.py
@@ -4,6 +4,7 @@
 
 """Timing utility."""
 
+import contextlib
 import datetime
 import functools
 import logging
@@ -25,34 +26,27 @@
     with Timer():
       code_to_be_timed()
 
-    with Timer(): -> logs "{formatted_delta}" at info level
-    with Timer('name'): -> logs "name: {formatted_delta}" at info
-    with Timer('name', print): -> prints "name: {formatted_delta}"
+    with Timer() as t: ->  str(t) == "{formatted_delta}"
+    with Timer('name') as t: -> str(t) == "name: {formatted_delta}"
 
-    If you don't want it to output itself on exit, you can do it manually,
-    e.g. to get an average:
+    To get an average:
 
     timers = []
     for _ in range(10):
-      with Timer(output=None) as t:
-        ...
+      with Timer() as t:
+        code_to_be_timed()
       timers.append(t)
     avg = sum(timers, start=Timer('Average')) / len(times)
     avg.output() -> prints "Average: {formatted_delta}"
   """
 
-  def __init__(self,
-               name: Optional[str] = None,
-               output: Optional[Callable[[str], Any]] = logging.info):
+  def __init__(self, name: Optional[str] = None):
     """Init.
 
     Args:
       name: A string to identify the timer, especially when using multiple.
-      output: A function that takes only a string to output it somewhere.
     """
     self.name = name
-    # Make output always callable, but do nothing when no output.
-    self.output = lambda: output(str(self)) if output else None
     self.start = 0.0
     self.end = 0.0
     self.delta = 0.0
@@ -60,7 +54,7 @@
   def __add__(self, other):
     if not isinstance(other, Timer):
       raise NotImplementedError(f'Cannot add {type(other)} to Timer')
-    result = Timer(self.name, self.output)
+    result = Timer(self.name)
     result.delta = self.delta + other.delta
 
     return result
@@ -68,7 +62,7 @@
   def __truediv__(self, other):
     if not isinstance(other, int):
       raise NotImplementedError(f'Only int is supported, given {type(other)}')
-    result = Timer(self.name, self.output)
+    result = Timer(self.name)
     result.delta = self.delta / other
 
     return result
@@ -80,24 +74,33 @@
   def __exit__(self, *args):
     self.end = time.perf_counter()
     self.delta = self.end - self.start
-    self.output()
 
   def __str__(self):
     name = f'{self.name}: ' if self.name else ''
     return f'{name}{pformat.timedelta(datetime.timedelta(seconds=self.delta))}'
 
 
-def timer(name: Optional[str] = None,
+def timed(name: Optional[str] = None,
           output: Callable[[str], Any] = logging.info):
-  """Timer decorator."""
+  """Timed decorator to add a timer to a function."""
 
   def decorator(func):
 
     @functools.wraps(func)
     def wrapper(*args, **kwargs):
-      with Timer(name, output):
+      with timer(name or func.__name__, output):
         return func(*args, **kwargs)
 
     return wrapper
 
   return decorator
+
+
+@contextlib.contextmanager
+def timer(name: str = None, output: Callable[[str], Any] = logging.info):
+  """Timer context manager to automatically output results."""
+  try:
+    with Timer(name) as t:
+      yield t
+  finally:
+    output(str(t))
diff --git a/utils/timer_unittest.py b/utils/timer_unittest.py
index 22e8c16..1f76efc 100644
--- a/utils/timer_unittest.py
+++ b/utils/timer_unittest.py
@@ -6,6 +6,7 @@
 
 import time
 
+from chromite.utils import pformat
 from chromite.utils import timer
 
 
@@ -20,7 +21,7 @@
 
   monkeypatch.setattr(time, 'perf_counter', time_mock)
 
-  with timer.Timer() as t:
+  with timer.timer() as t:
     pass
 
   assert t.delta == 1.0
@@ -45,3 +46,32 @@
 
   assert sum(timers, start=timer.Timer()).delta == 10.0
   assert (sum(timers, start=timer.Timer()) / len(timers)).delta == 1.0
+
+
+def test_timer_decorator(monkeypatch):
+  """Test the timed decorator."""
+  delta = '1s'
+  name = 'name'
+  output_fn_called = False
+
+  # monkeypatch the timedelta formatter to return the expected delta.
+  def timedelta_mock(*_args, **_kwargs):
+    return delta
+
+  monkeypatch.setattr(pformat, 'timedelta', timedelta_mock)
+
+  # Output function to check the value.
+  def output_fn(value):
+    nonlocal output_fn_called
+    output_fn_called = True
+    assert value == f'{name}: {delta}'
+
+  # The decorated function.
+  @timer.timed(name, output_fn)
+  def timed_fn():
+    pass
+
+  # Run the function to trigger the test.
+  timed_fn()
+
+  assert output_fn_called