Reland "pw_presubmit: Move most logic to a module"

This is a reland of 618497de3d75d46f0eb52aac984cca10c41c3349

Differences from the original CL:
* pwrev/67821 has landed and this CL moves it to the new module
* pwirev/17540 has landed

Original change's description:
> pw_presubmit: Move most logic to a module
>
> Move most logic from the pw_presubmit recipe to a module. For now, leave
> the signing and upload logic in the recipe.
>
> Bug: 523
> Change-Id: I413cb9e757c98d09a9896d4466012f825e80c0f1
> Reviewed-on: https://pigweed-review.googlesource.com/c/infra/recipes/+/67229
> Commit-Queue: Rob Mohr <mohrr@google.com>
> Reviewed-by: Oliver Newman <olivernewman@google.com>

Bug: 523
Change-Id: I455d49b25412f70826bda94600ad532ff1f27a37
Reviewed-on: https://pigweed-review.googlesource.com/c/infra/recipes/+/67820
Reviewed-by: Ted Pudlik <tpudlik@google.com>
Commit-Queue: Rob Mohr <mohrr@google.com>
diff --git a/recipe_modules/pw_presubmit/__init__.py b/recipe_modules/pw_presubmit/__init__.py
new file mode 100644
index 0000000..ed7bf1a
--- /dev/null
+++ b/recipe_modules/pw_presubmit/__init__.py
@@ -0,0 +1,32 @@
+# Copyright 2021 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+# pylint: disable=missing-docstring
+
+from PB.recipe_modules.pigweed.pw_presubmit import properties
+
+DEPS = [
+    'fuchsia/utils',
+    'pigweed/build',
+    'recipe_engine/buildbucket',
+    'recipe_engine/file',
+    'recipe_engine/path',
+    'recipe_engine/raw_io',
+    'recipe_engine/step',
+    'recipe_engine/time',
+]
+
+PROPERTIES = properties.InputProperties
+
+PYTHON_VERSION_COMPATIBILITY = "PY3"
diff --git a/recipe_modules/pw_presubmit/api.py b/recipe_modules/pw_presubmit/api.py
new file mode 100644
index 0000000..82789c4
--- /dev/null
+++ b/recipe_modules/pw_presubmit/api.py
@@ -0,0 +1,177 @@
+# Copyright 2021 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+"""Wrapper for 'pw presubmit' in the project source tree."""
+
+import collections
+
+import attr
+from recipe_engine import config_types, recipe_api
+from RECIPE_MODULES.fuchsia.utils import memoize
+
+
+@attr.s
+class Step(object):
+    _api = attr.ib()
+    name = attr.ib()
+    dir = attr.ib()
+    _export_dir_name = attr.ib(default=None)
+
+    @property
+    def export_dir(self):
+        if not self._export_dir_name:
+            return None  # pragma: no cover
+        return self.dir.join(self._export_dir_name)
+
+
+class PwPresubmitApi(recipe_api.RecipeApi):
+    """Calls to checkout code."""
+
+    def __init__(self, props, *args, **kwargs):
+        super(PwPresubmitApi, self).__init__(*args, **kwargs)
+        self._command_name = props.command_name or 'python -m pw_cli'
+        self._input_steps = list(props.step)
+        self._input_programs = list(props.program)
+        self._only_on_changed_files = props.only_on_changed_files
+        self._export_dir_name = props.export_dir_name
+        self._root = None
+        self._checkout_root = None
+        self._step_objects = None
+
+    @property
+    def command_name(self):
+        return self._command_name
+
+    @property
+    def root(self):
+        return self._root
+
+    @property
+    def export_dir_name(self):
+        return self._export_dir_name
+
+    def _step(self, name):
+        return Step(
+            self.m,
+            name,
+            self.root.join(name),
+            export_dir_name=self.export_dir_name,
+        )
+
+    def init(self, checkout_root):
+        if not self._input_steps and not self._input_programs:
+            raise self.m.step.StepFailure('no step or program properties')
+
+        self._root = self.m.path['start_dir'].join('presubmit')
+        self._checkout_root = checkout_root
+
+        self._step_objects = collections.OrderedDict()
+
+        for step_name in self._input_steps:
+            self._step_objects[step_name] = self._step(step_name)
+
+        if self._input_programs:
+            with self.m.step.nest('get steps from programs'):
+                for program in self._input_programs:
+                    # To get step_test_data line to pass pylint.
+                    raw_io_stream_output = (
+                        self.m.raw_io.test_api.stream_output_text
+                    )
+
+                    program_steps = (
+                        self._run(
+                            ['--program', program, '--only-list-steps'],
+                            name=program,
+                            stdout=self.m.raw_io.output_text(),
+                            step_test_data=lambda: raw_io_stream_output(
+                                '{0}_0\n{0}_1\n'.format(program),
+                            ),
+                        )
+                        .stdout.strip()
+                        .splitlines()
+                    )
+
+                    for step_name in program_steps:
+                        self._step_objects[step_name] = self._step(step_name)
+
+        if not self._step_objects:
+            raise self.m.step.StepFailure('no steps to execute')
+
+    def steps(self):
+        # We shouldn't get to here, but in case the caller doesn't call init()
+        # first we'll check anyway.
+        if not self._step_objects:  # pragma: no cover
+            raise self.m.step.StepFailure('no steps to execute')
+
+        return self._step_objects.values()
+
+    def _step_timeout(self):
+        # Amount of time elapsed in the run.
+        elapsed_time = (
+            self.m.time.time() - self.m.buildbucket.build.start_time.seconds
+        )
+
+        # Amount of time before build times out.
+        time_remaining = (
+            self.m.buildbucket.build.execution_timeout.seconds - elapsed_time
+        )
+
+        # Give a buffer before build times out and kill this step then. This
+        # should give enough time to read any logfiles and maybe upload to
+        # logdog/GCS before the build times out.
+        step_timeout = time_remaining - 60
+
+        # If the timeout would be negative or very small set it to 30 seconds.
+        # We likely won't have enough information to debug these steps, but in
+        # case they're fast there's no reason to kill them much before the
+        # build is terminated.
+        if step_timeout < 30:
+            step_timeout = 30
+
+        return step_timeout
+
+    def _run(self, args, name='run', **kwargs):
+        cmd = self._command_name.split()
+        cmd += [
+            '--directory',
+            self._checkout_root,
+            '--loglevel',
+            'debug',
+            'presubmit',
+            '--package-root',
+            self.m.path['cache'],
+            '--output-directory',
+            self._root,
+        ]
+
+        cmd.extend(args)
+
+        return self.m.step(name, cmd, timeout=self._step_timeout(), **kwargs)
+
+    def run(self, step):
+        with self.m.step.nest(step.name) as pres:
+            args = []
+
+            if self._only_on_changed_files:
+                args.extend(('--base', 'HEAD~1'))
+
+            args.extend(('--step', step.name))
+
+            self._run(args, name=step.name)
+
+            if step.export_dir:
+                self.m.file.ensure_directory(
+                    'mkdir {}'.format(self.export_dir_name), step.export_dir,
+                )
+
+            self.m.build.save_logs(step.dir, step.export_dir)
diff --git a/recipe_modules/pw_presubmit/properties.proto b/recipe_modules/pw_presubmit/properties.proto
new file mode 100644
index 0000000..6b5a526
--- /dev/null
+++ b/recipe_modules/pw_presubmit/properties.proto
@@ -0,0 +1,40 @@
+// Copyright 2021 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+syntax = "proto3";
+
+// This message is used for both the pw_presubmit and pw_presubmit_container
+// recipes.
+package recipe_modules.pigweed.pw_presubmit;
+
+message InputProperties {
+  // Command name in case it's changed by a dependent project. Default if unset
+  // is "pw".
+  string command_name = 1;
+
+  // Step to run from 'pw presubmit'. See 'pw presubmit --help' for options.
+  // Default is to run all steps.
+  repeated string step = 2;
+
+  // Program to run from 'pw presubmit'. See 'pw presubmit --help' for options.
+  // Default is to let 'pw presubmit' run its default program.
+  repeated string program = 3;
+
+  // Only run this check against changed files.
+  bool only_on_changed_files = 4;
+
+  // Subdirectory of the build directory to upload to GCS. Required to upload
+  // build artifacts.
+  string export_dir_name = 5;
+}
diff --git a/recipe_modules/pw_presubmit/test_api.py b/recipe_modules/pw_presubmit/test_api.py
new file mode 100644
index 0000000..d6ee7a4
--- /dev/null
+++ b/recipe_modules/pw_presubmit/test_api.py
@@ -0,0 +1,36 @@
+# Copyright 2021 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+"""Test API for pw_presubmit."""
+
+import re
+
+from PB.recipe_modules.pigweed.pw_presubmit import properties
+from recipe_engine import recipe_test_api
+
+
+class PwPresubmitTestApi(recipe_test_api.RecipeTestApi):
+    """Test API for pw_presubmit."""
+
+    def properties(self, **kwargs):
+        props = {
+            'command_name': None,
+            'program': [],
+            'step': [],
+            'only_on_changed_files': False,
+            'export_dir_name': 'export',
+        }
+
+        props.update(**kwargs)
+
+        return {'$pigweed/pw_presubmit': properties.InputProperties(**props)}
diff --git a/recipe_modules/pw_presubmit/tests/full.expected/empty-program.json b/recipe_modules/pw_presubmit/tests/full.expected/empty-program.json
new file mode 100644
index 0000000..e0023f1
--- /dev/null
+++ b/recipe_modules/pw_presubmit/tests/full.expected/empty-program.json
@@ -0,0 +1,37 @@
+[
+  {
+    "cmd": [],
+    "name": "get steps from programs"
+  },
+  {
+    "cmd": [
+      "python",
+      "-m",
+      "pw_cli",
+      "--directory",
+      "[START_DIR]/checkout",
+      "--loglevel",
+      "debug",
+      "presubmit",
+      "--package-root",
+      "[CACHE]",
+      "--output-directory",
+      "[START_DIR]/presubmit",
+      "--program",
+      "empty",
+      "--only-list-steps"
+    ],
+    "name": "get steps from programs.empty",
+    "timeout": 30,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "failure": {
+      "failure": {},
+      "humanReason": "no steps to execute"
+    },
+    "name": "$result"
+  }
+]
\ No newline at end of file
diff --git a/recipe_modules/pw_presubmit/tests/full.expected/no-steps.json b/recipe_modules/pw_presubmit/tests/full.expected/no-steps.json
new file mode 100644
index 0000000..cf2c23a
--- /dev/null
+++ b/recipe_modules/pw_presubmit/tests/full.expected/no-steps.json
@@ -0,0 +1,9 @@
+[
+  {
+    "failure": {
+      "failure": {},
+      "humanReason": "no step or program properties"
+    },
+    "name": "$result"
+  }
+]
\ No newline at end of file
diff --git a/recipe_modules/pw_presubmit/tests/full.expected/pigweed.json b/recipe_modules/pw_presubmit/tests/full.expected/pigweed.json
new file mode 100644
index 0000000..4f49c10
--- /dev/null
+++ b/recipe_modules/pw_presubmit/tests/full.expected/pigweed.json
@@ -0,0 +1,385 @@
+[
+  {
+    "cmd": [],
+    "name": "get steps from programs"
+  },
+  {
+    "cmd": [
+      "foo",
+      "--directory",
+      "[START_DIR]/checkout",
+      "--loglevel",
+      "debug",
+      "presubmit",
+      "--package-root",
+      "[CACHE]",
+      "--output-directory",
+      "[START_DIR]/presubmit",
+      "--program",
+      "full",
+      "--only-list-steps"
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "get steps from programs.full",
+    "timeout": 30,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "full_0"
+  },
+  {
+    "cmd": [
+      "foo",
+      "--directory",
+      "[START_DIR]/checkout",
+      "--loglevel",
+      "debug",
+      "presubmit",
+      "--package-root",
+      "[CACHE]",
+      "--output-directory",
+      "[START_DIR]/presubmit",
+      "--base",
+      "HEAD~1",
+      "--step",
+      "full_0"
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "full_0.full_0",
+    "timeout": 30,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0777",
+      "[START_DIR]/presubmit/full_0/export"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "full_0.mkdir export",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[START_DIR]/presubmit/full_0/ninja.log",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "full_0.ninja.log",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@ninja.log@2000 5000 0 medium 0@@@",
+      "@@@STEP_LOG_LINE@ninja.log@3000 8000 0 long 0@@@",
+      "@@@STEP_LOG_LINE@ninja.log@malformed line@@@",
+      "@@@STEP_LOG_LINE@ninja.log@4000 5000 0 short 0@@@",
+      "@@@STEP_LOG_LINE@ninja.log@5000 x 0 malformed-end-time 0@@@",
+      "@@@STEP_LOG_END@ninja.log@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "full_0.longest build steps",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "full_0.longest build steps.long",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_SUMMARY_TEXT@5.0s@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "full_0.longest build steps.medium",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_SUMMARY_TEXT@3.0s@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "full_0.longest build steps.short",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_SUMMARY_TEXT@1.0s@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "full_0.copy",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[START_DIR]/presubmit/full_0/ninja.log",
+      "[START_DIR]/presubmit/full_0/export/ninja.log"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "full_0.copy.ninja.log",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "full_1"
+  },
+  {
+    "cmd": [
+      "foo",
+      "--directory",
+      "[START_DIR]/checkout",
+      "--loglevel",
+      "debug",
+      "presubmit",
+      "--package-root",
+      "[CACHE]",
+      "--output-directory",
+      "[START_DIR]/presubmit",
+      "--base",
+      "HEAD~1",
+      "--step",
+      "full_1"
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "full_1.full_1",
+    "timeout": 30,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0777",
+      "[START_DIR]/presubmit/full_1/export"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "full_1.mkdir export",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[START_DIR]/presubmit/full_1/ninja.log",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "full_1.ninja.log",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@ninja.log@2000 5000 0 medium 0@@@",
+      "@@@STEP_LOG_LINE@ninja.log@3000 8000 0 long 0@@@",
+      "@@@STEP_LOG_LINE@ninja.log@malformed line@@@",
+      "@@@STEP_LOG_LINE@ninja.log@4000 5000 0 short 0@@@",
+      "@@@STEP_LOG_LINE@ninja.log@5000 x 0 malformed-end-time 0@@@",
+      "@@@STEP_LOG_END@ninja.log@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "full_1.longest build steps",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "full_1.longest build steps.long",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_SUMMARY_TEXT@5.0s@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "full_1.longest build steps.medium",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_SUMMARY_TEXT@3.0s@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "full_1.longest build steps.short",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_SUMMARY_TEXT@1.0s@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "full_1.copy",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[START_DIR]/presubmit/full_1/ninja.log",
+      "[START_DIR]/presubmit/full_1/export/ninja.log"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "full_1.copy.ninja.log",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "name": "$result"
+  }
+]
\ No newline at end of file
diff --git a/recipe_modules/pw_presubmit/tests/full.expected/step.json b/recipe_modules/pw_presubmit/tests/full.expected/step.json
new file mode 100644
index 0000000..fef6a49
--- /dev/null
+++ b/recipe_modules/pw_presubmit/tests/full.expected/step.json
@@ -0,0 +1,347 @@
+[
+  {
+    "cmd": [],
+    "name": "step1"
+  },
+  {
+    "cmd": [
+      "python",
+      "-m",
+      "pw_cli",
+      "--directory",
+      "[START_DIR]/checkout",
+      "--loglevel",
+      "debug",
+      "presubmit",
+      "--package-root",
+      "[CACHE]",
+      "--output-directory",
+      "[START_DIR]/presubmit",
+      "--step",
+      "step1"
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "project:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "step1.step1",
+    "timeout": 40.0,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0777",
+      "[START_DIR]/presubmit/step1/export"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "step1.mkdir export",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[START_DIR]/presubmit/step1/ninja.log",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "step1.ninja.log",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@ninja.log@2000 5000 0 medium 0@@@",
+      "@@@STEP_LOG_LINE@ninja.log@3000 8000 0 long 0@@@",
+      "@@@STEP_LOG_LINE@ninja.log@malformed line@@@",
+      "@@@STEP_LOG_LINE@ninja.log@4000 5000 0 short 0@@@",
+      "@@@STEP_LOG_LINE@ninja.log@5000 x 0 malformed-end-time 0@@@",
+      "@@@STEP_LOG_END@ninja.log@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "step1.longest build steps",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "step1.longest build steps.long",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_SUMMARY_TEXT@5.0s@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "step1.longest build steps.medium",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_SUMMARY_TEXT@3.0s@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "step1.longest build steps.short",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_SUMMARY_TEXT@1.0s@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "step1.copy",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[START_DIR]/presubmit/step1/ninja.log",
+      "[START_DIR]/presubmit/step1/export/ninja.log"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "step1.copy.ninja.log",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "step2"
+  },
+  {
+    "cmd": [
+      "python",
+      "-m",
+      "pw_cli",
+      "--directory",
+      "[START_DIR]/checkout",
+      "--loglevel",
+      "debug",
+      "presubmit",
+      "--package-root",
+      "[CACHE]",
+      "--output-directory",
+      "[START_DIR]/presubmit",
+      "--step",
+      "step2"
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "project:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "step2.step2",
+    "timeout": 30,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0777",
+      "[START_DIR]/presubmit/step2/export"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "step2.mkdir export",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[START_DIR]/presubmit/step2/ninja.log",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "step2.ninja.log",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@ninja.log@2000 5000 0 medium 0@@@",
+      "@@@STEP_LOG_LINE@ninja.log@3000 8000 0 long 0@@@",
+      "@@@STEP_LOG_LINE@ninja.log@malformed line@@@",
+      "@@@STEP_LOG_LINE@ninja.log@4000 5000 0 short 0@@@",
+      "@@@STEP_LOG_LINE@ninja.log@5000 x 0 malformed-end-time 0@@@",
+      "@@@STEP_LOG_END@ninja.log@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "step2.longest build steps",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "step2.longest build steps.long",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_SUMMARY_TEXT@5.0s@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "step2.longest build steps.medium",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_SUMMARY_TEXT@3.0s@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "step2.longest build steps.short",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_SUMMARY_TEXT@1.0s@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "step2.copy",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[START_DIR]/presubmit/step2/ninja.log",
+      "[START_DIR]/presubmit/step2/export/ninja.log"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "step2.copy.ninja.log",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "name": "$result"
+  }
+]
\ No newline at end of file
diff --git a/recipe_modules/pw_presubmit/tests/full.py b/recipe_modules/pw_presubmit/tests/full.py
new file mode 100644
index 0000000..b40ac59
--- /dev/null
+++ b/recipe_modules/pw_presubmit/tests/full.py
@@ -0,0 +1,83 @@
+# Copyright 2021 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+"""Full test of pw_presubmit module."""
+
+import datetime
+
+from recipe_engine.recipe_api import Property
+
+DEPS = [
+    'fuchsia/status_check',
+    'pigweed/checkout',
+    'pigweed/pw_presubmit',
+    'recipe_engine/path',
+    'recipe_engine/properties',
+    'recipe_engine/raw_io',
+    'recipe_engine/time',
+]
+
+PYTHON_VERSION_COMPATIBILITY = "PY3"
+
+
+def RunSteps(api):  # pylint: disable=invalid-name
+    api.pw_presubmit.init(api.path['start_dir'].join('checkout'))
+
+    for step in api.pw_presubmit.steps():
+        api.pw_presubmit.run(step)
+
+    # For coverage.
+    _ = api.pw_presubmit.command_name
+    _ = api.pw_presubmit.root
+
+
+def GenTests(api):  # pylint: disable=invalid-name
+    """Create tests."""
+
+    def properties(**kwargs):
+        new_kwargs = api.checkout.git_properties()
+        new_kwargs.update(api.pw_presubmit.properties(**kwargs))
+        return api.properties(**new_kwargs)
+
+    yield (
+        api.status_check.test('no-steps', status='failure')
+        + properties()
+        + api.checkout.ci_test_data()
+    )
+
+    yield (
+        api.status_check.test('empty-program', status='failure')
+        + properties(program=['empty'])
+        + api.step_data(
+            "get steps from programs.empty", stdout=api.raw_io.output_text(''),
+        )
+    )
+
+    yield (
+        api.status_check.test('pigweed')
+        + properties(
+            command_name='foo', program=['full'], only_on_changed_files=True
+        )
+        + api.checkout.ci_test_data()
+    )
+
+    yield (
+        api.status_check.test('step')
+        + properties(step=['step1', 'step2'])
+        + api.checkout.try_test_data(
+            start_time=datetime.datetime.utcfromtimestamp(1600000000),
+            execution_timeout=120,
+        )
+        + api.time.seed(1600000000)
+        + api.time.step(20.0)
+    )
diff --git a/recipes/pw_presubmit.expected/empty-program.json b/recipes/pw_presubmit.expected/empty-program.json
deleted file mode 100644
index 3d198ab..0000000
--- a/recipes/pw_presubmit.expected/empty-program.json
+++ /dev/null
@@ -1,745 +0,0 @@
-[
-  {
-    "cmd": [],
-    "name": "checkout pigweed",
-    "~followup_annotations": [
-      "@@@STEP_LINK@applied pigweed:1234@https://pigweed-review.googlesource.com/c/1234@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.change data",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "ls-remote",
-      "--heads",
-      "https://pigweed.googlesource.com/pigweed/pigweed",
-      "main"
-    ],
-    "name": "checkout pigweed.change data.git ls-remote",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.change data.ensure gerrit",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "RECIPE_MODULE[fuchsia::gerrit]/resources/tool_manifest.json",
-      "/path/to/tmp/json"
-    ],
-    "infra_step": true,
-    "name": "checkout pigweed.change data.ensure gerrit.read manifest",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@",
-      "@@@STEP_LOG_LINE@tool_manifest.json@{@@@",
-      "@@@STEP_LOG_LINE@tool_manifest.json@  \"path\": \"path/to/gerrit\",@@@",
-      "@@@STEP_LOG_LINE@tool_manifest.json@  \"version\": \"version:pinned-version\"@@@",
-      "@@@STEP_LOG_LINE@tool_manifest.json@}@@@",
-      "@@@STEP_LOG_END@tool_manifest.json@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.change data.ensure gerrit.install path/to/gerrit",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0777",
-      "[CACHE]/cipd/path/to/gerrit/version%3Apinned-version"
-    ],
-    "infra_step": true,
-    "name": "checkout pigweed.change data.ensure gerrit.install path/to/gerrit.ensure package directory",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@4@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "cipd",
-      "ensure",
-      "-root",
-      "[CACHE]/cipd/path/to/gerrit/version%3Apinned-version",
-      "-ensure-file",
-      "path/to/gerrit version:pinned-version",
-      "-max-threads",
-      "0",
-      "-json-output",
-      "/path/to/tmp/json"
-    ],
-    "infra_step": true,
-    "name": "checkout pigweed.change data.ensure gerrit.install path/to/gerrit.ensure_installed",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@4@@@",
-      "@@@STEP_LOG_LINE@json.output@{@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\", @@@",
-      "@@@STEP_LOG_LINE@json.output@        \"package\": \"path/to/gerrit\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      }@@@",
-      "@@@STEP_LOG_LINE@json.output@    ]@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@}@@@",
-      "@@@STEP_LOG_END@json.output@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "[CACHE]/cipd/path/to/gerrit/version%3Apinned-version/gerrit",
-      "change-query",
-      "-host",
-      "https://pigweed-review.googlesource.com",
-      "-input",
-      "{\"params\": {\"q\": \"commit:h3ll0\"}}",
-      "-output",
-      "/path/to/tmp/json"
-    ],
-    "name": "checkout pigweed.change data.number",
-    "timeout": 30,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@",
-      "@@@STEP_LOG_LINE@json.output@[@@@",
-      "@@@STEP_LOG_LINE@json.output@  {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"_number\": \"1234\", @@@",
-      "@@@STEP_LOG_LINE@json.output@    \"branch\": \"main\"@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@]@@@",
-      "@@@STEP_LOG_END@json.output@@@",
-      "@@@STEP_LOG_LINE@json.input@{@@@",
-      "@@@STEP_LOG_LINE@json.input@  \"params\": {@@@",
-      "@@@STEP_LOG_LINE@json.input@    \"q\": \"commit:h3ll0\"@@@",
-      "@@@STEP_LOG_LINE@json.input@  }@@@",
-      "@@@STEP_LOG_LINE@json.input@}@@@",
-      "@@@STEP_LOG_END@json.input@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.change data.changes",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.change data.changes.pigweed:1234",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@",
-      "@@@STEP_SUMMARY_TEXT@_Change(number=1234, remote='https://pigweed.googlesource.com/pigweed/pigweed', ref='h3ll0', rebase=False, branch='main', gerrit_name='pigweed', submitted=True, base=None, base_type=None)@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0777",
-      "[START_DIR]/checkout"
-    ],
-    "infra_step": true,
-    "name": "checkout pigweed.makedirs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "init"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "name": "checkout pigweed.git init",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "remote",
-      "add",
-      "origin",
-      "https://pigweed.googlesource.com/pigweed/pigweed"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "name": "checkout pigweed.git remote",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "name": "checkout pigweed.set fetch.uriprotocols",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "",
-      "[CACHE]/git/.GUARD_FILE"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "name": "checkout pigweed.cache.write guard file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@",
-      "@@@STEP_LOG_END@.GUARD_FILE@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0777",
-      "[CACHE]/git/pigweed.googlesource.com-pigweed-pigweed"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "name": "checkout pigweed.cache.makedirs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "init",
-      "--bare"
-    ],
-    "cwd": "[CACHE]/git/pigweed.googlesource.com-pigweed-pigweed",
-    "infra_step": true,
-    "name": "checkout pigweed.cache.git init",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "remote.origin.url",
-      "https://pigweed.googlesource.com/pigweed/pigweed"
-    ],
-    "cwd": "[CACHE]/git/pigweed.googlesource.com-pigweed-pigweed",
-    "infra_step": true,
-    "name": "checkout pigweed.cache.remote set-url",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[CACHE]/git/pigweed.googlesource.com-pigweed-pigweed",
-    "infra_step": true,
-    "name": "checkout pigweed.cache.set fetch.uriprotocols",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "--replace-all",
-      "remote.origin.fetch",
-      "+refs/heads/*:refs/heads/*",
-      "\\+refs/heads/\\*:.*"
-    ],
-    "cwd": "[CACHE]/git/pigweed.googlesource.com-pigweed-pigweed",
-    "infra_step": true,
-    "name": "checkout pigweed.cache.replace fetch configs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--prune",
-      "--tags",
-      "origin"
-    ],
-    "cwd": "[CACHE]/git/pigweed.googlesource.com-pigweed-pigweed",
-    "infra_step": true,
-    "name": "checkout pigweed.cache.git fetch",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0777",
-      "[START_DIR]/checkout/.git/objects/info"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "name": "checkout pigweed.cache.makedirs object/info",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "[CACHE]/git/pigweed.googlesource.com-pigweed-pigweed/objects\n",
-      "[START_DIR]/checkout/.git/objects/info/alternates"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "name": "checkout pigweed.cache.alternates",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@",
-      "@@@STEP_LOG_LINE@alternates@[CACHE]/git/pigweed.googlesource.com-pigweed-pigweed/objects@@@",
-      "@@@STEP_LOG_END@alternates@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "remove",
-      "[CACHE]/git/.GUARD_FILE"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "name": "checkout pigweed.cache.remove guard file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--tags",
-      "origin",
-      "main",
-      "--recurse-submodules"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "name": "checkout pigweed.git fetch",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "checkout",
-      "-f",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "name": "checkout pigweed.git checkout",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "rev-parse",
-      "HEAD"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "name": "checkout pigweed.git rev-parse",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-d",
-      "-x"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "name": "checkout pigweed.git clean",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.submodule",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "sync"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "name": "checkout pigweed.submodule.git submodule sync",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "update",
-      "--init",
-      "--recursive"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "name": "checkout pigweed.submodule.git submodule update",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "rev-parse",
-      "HEAD"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "name": "checkout pigweed.git rev-parse (2)",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.apply pigweed:1234",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LINK@gerrit@https://pigweed-review.googlesource.com/c/1234@@@",
-      "@@@STEP_LINK@gitiles@https://pigweed.googlesource.com/pigweed/pigweed/+/h3ll0@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "https://pigweed.googlesource.com/pigweed/pigweed",
-      "h3ll0",
-      "--no-recurse-submodules"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "name": "checkout pigweed.apply pigweed:1234.git fetch patch",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "checkout",
-      "--force",
-      "-b",
-      "working",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "name": "checkout pigweed.apply pigweed:1234.git checkout patch",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "rev-parse",
-      "HEAD"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "name": "checkout pigweed.apply pigweed:1234.git rev-parse",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "update",
-      "--init",
-      "--recursive"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "name": "checkout pigweed.apply pigweed:1234.git submodule update",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "status",
-      "--recursive"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "name": "checkout pigweed.git submodule status",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.status",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@applied [_Change(number=1234, remote='https://pigweed.googlesource.com/pigweed/pigweed', ref='h3ll0', rebase=False, branch='main', gerrit_name='pigweed', submitted=True, base='HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_', base_type='submitted_commit_hash')]\nnot applied []@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.git log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "name": "checkout pigweed.git log.[START_DIR]/checkout",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.base",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@SET_BUILD_PROPERTY@got_revision@\"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\"@@@",
-      "@@@SET_BUILD_PROPERTY@got_revision_type@\"submitted_commit_hash\"@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0777",
-      "[START_DIR]/snapshot"
-    ],
-    "infra_step": true,
-    "name": "checkout pigweed.mkdir",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "status",
-      "--recursive"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "name": "checkout pigweed.submodule-status",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "submodule status filler text",
-      "[START_DIR]/snapshot/submodules.log"
-    ],
-    "infra_step": true,
-    "name": "checkout pigweed.write submodule snapshot",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@submodules.log@submodule status filler text@@@",
-      "@@@STEP_LOG_END@submodules.log@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "name": "checkout pigweed.log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "",
-      "[START_DIR]/snapshot/git.log"
-    ],
-    "infra_step": true,
-    "name": "checkout pigweed.write git log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_END@git.log@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "environment"
-  },
-  {
-    "cmd": [],
-    "name": "get steps from programs"
-  },
-  {
-    "cmd": [
-      "python",
-      "-m",
-      "pw_cli",
-      "--directory",
-      "[START_DIR]/checkout",
-      "--loglevel",
-      "debug",
-      "presubmit",
-      "--package-root",
-      "[CACHE]",
-      "--output-directory",
-      "[START_DIR]/presubmit",
-      "--program",
-      "empty",
-      "--only-list-steps"
-    ],
-    "env": {
-      "BUILDBUCKET_ID": "0",
-      "BUILDBUCKET_NAME": "project:bucket:builder",
-      "BUILD_NUMBER": "0",
-      "GOCACHE": "[CACHE]/go",
-      "PIP_CACHE_DIR": "[CACHE]/pip",
-      "PW_ENVIRONMENT_NO_ERROR_ON_UNRECOGNIZED": "1",
-      "PW_ENVSETUP_DISABLE_SPINNER": "1",
-      "PW_PRESUBMIT_DISABLE_SUBPROCESS_CAPTURE": "1",
-      "PW_PROJECT_ROOT": "[START_DIR]/checkout",
-      "PW_ROOT": "[START_DIR]/checkout",
-      "TEST_TMPDIR": "[CACHE]/bazel"
-    },
-    "name": "get steps from programs.empty",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "failure": {
-      "failure": {},
-      "humanReason": "no steps to execute"
-    },
-    "name": "$result"
-  }
-]
\ No newline at end of file
diff --git a/recipes/pw_presubmit.expected/no-steps.json b/recipes/pw_presubmit.expected/no-steps.json
deleted file mode 100644
index cae0ef0..0000000
--- a/recipes/pw_presubmit.expected/no-steps.json
+++ /dev/null
@@ -1,1127 +0,0 @@
-[
-  {
-    "cmd": [],
-    "name": "checkout pigweed",
-    "~followup_annotations": [
-      "@@@STEP_LINK@applied pigweed:1234@https://pigweed-review.googlesource.com/c/1234@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.change data",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.change data.process gitiles commit",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.change data.process gitiles commit.ensure gerrit",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "RECIPE_MODULE[fuchsia::gerrit]/resources/tool_manifest.json",
-      "/path/to/tmp/json"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.change data.process gitiles commit.ensure gerrit.read manifest",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@4@@@",
-      "@@@STEP_LOG_LINE@tool_manifest.json@{@@@",
-      "@@@STEP_LOG_LINE@tool_manifest.json@  \"path\": \"path/to/gerrit\",@@@",
-      "@@@STEP_LOG_LINE@tool_manifest.json@  \"version\": \"version:pinned-version\"@@@",
-      "@@@STEP_LOG_LINE@tool_manifest.json@}@@@",
-      "@@@STEP_LOG_END@tool_manifest.json@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.change data.process gitiles commit.ensure gerrit.install path/to/gerrit",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@4@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0777",
-      "[CACHE]/cipd/path/to/gerrit/version%3Apinned-version"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.change data.process gitiles commit.ensure gerrit.install path/to/gerrit.ensure package directory",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@5@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "cipd",
-      "ensure",
-      "-root",
-      "[CACHE]/cipd/path/to/gerrit/version%3Apinned-version",
-      "-ensure-file",
-      "path/to/gerrit version:pinned-version",
-      "-max-threads",
-      "0",
-      "-json-output",
-      "/path/to/tmp/json"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.change data.process gitiles commit.ensure gerrit.install path/to/gerrit.ensure_installed",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@5@@@",
-      "@@@STEP_LOG_LINE@json.output@{@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\", @@@",
-      "@@@STEP_LOG_LINE@json.output@        \"package\": \"path/to/gerrit\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      }@@@",
-      "@@@STEP_LOG_LINE@json.output@    ]@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@}@@@",
-      "@@@STEP_LOG_END@json.output@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "[CACHE]/cipd/path/to/gerrit/version%3Apinned-version/gerrit",
-      "change-query",
-      "-host",
-      "https://pigweed-review.googlesource.com",
-      "-input",
-      "{\"params\": {\"q\": \"commit:2d72510e447ab60a9728aeea2362d8be2cbd7789\"}}",
-      "-output",
-      "/path/to/tmp/json"
-    ],
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.change data.process gitiles commit.number",
-    "timeout": 30,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@",
-      "@@@STEP_LOG_LINE@json.output@[@@@",
-      "@@@STEP_LOG_LINE@json.output@  {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"_number\": \"1234\", @@@",
-      "@@@STEP_LOG_LINE@json.output@    \"branch\": \"main\"@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@]@@@",
-      "@@@STEP_LOG_END@json.output@@@",
-      "@@@STEP_LOG_LINE@json.input@{@@@",
-      "@@@STEP_LOG_LINE@json.input@  \"params\": {@@@",
-      "@@@STEP_LOG_LINE@json.input@    \"q\": \"commit:2d72510e447ab60a9728aeea2362d8be2cbd7789\"@@@",
-      "@@@STEP_LOG_LINE@json.input@  }@@@",
-      "@@@STEP_LOG_LINE@json.input@}@@@",
-      "@@@STEP_LOG_END@json.input@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.change data.changes",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.change data.changes.pigweed:1234",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@",
-      "@@@STEP_SUMMARY_TEXT@_Change(number=1234, remote='https://pigweed.googlesource.com/pigweed/pigweed', ref='2d72510e447ab60a9728aeea2362d8be2cbd7789', rebase=False, branch='main', gerrit_name='pigweed', submitted=True, base=None, base_type=None)@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0777",
-      "[START_DIR]/checkout"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.makedirs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "init"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.git init",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "remote",
-      "add",
-      "origin",
-      "https://pigweed.googlesource.com/pigweed/pigweed"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.git remote",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.set fetch.uriprotocols",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "",
-      "[CACHE]/git/.GUARD_FILE"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.cache.write guard file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@",
-      "@@@STEP_LOG_END@.GUARD_FILE@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0777",
-      "[CACHE]/git/pigweed.googlesource.com-pigweed-pigweed"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.cache.makedirs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "init",
-      "--bare"
-    ],
-    "cwd": "[CACHE]/git/pigweed.googlesource.com-pigweed-pigweed",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.cache.git init",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "remote.origin.url",
-      "https://pigweed.googlesource.com/pigweed/pigweed"
-    ],
-    "cwd": "[CACHE]/git/pigweed.googlesource.com-pigweed-pigweed",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.cache.remote set-url",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[CACHE]/git/pigweed.googlesource.com-pigweed-pigweed",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.cache.set fetch.uriprotocols",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "--replace-all",
-      "remote.origin.fetch",
-      "+refs/heads/*:refs/heads/*",
-      "\\+refs/heads/\\*:.*"
-    ],
-    "cwd": "[CACHE]/git/pigweed.googlesource.com-pigweed-pigweed",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.cache.replace fetch configs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--prune",
-      "--tags",
-      "origin"
-    ],
-    "cwd": "[CACHE]/git/pigweed.googlesource.com-pigweed-pigweed",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.cache.git fetch",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0777",
-      "[START_DIR]/checkout/.git/objects/info"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.cache.makedirs object/info",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "[CACHE]/git/pigweed.googlesource.com-pigweed-pigweed/objects\n",
-      "[START_DIR]/checkout/.git/objects/info/alternates"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.cache.alternates",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@",
-      "@@@STEP_LOG_LINE@alternates@[CACHE]/git/pigweed.googlesource.com-pigweed-pigweed/objects@@@",
-      "@@@STEP_LOG_END@alternates@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "remove",
-      "[CACHE]/git/.GUARD_FILE"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.cache.remove guard file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--tags",
-      "origin",
-      "main",
-      "--recurse-submodules"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.git fetch",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "checkout",
-      "-f",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.git checkout",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "rev-parse",
-      "HEAD"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.git rev-parse",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-d",
-      "-x"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.git clean",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.submodule",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "sync"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.submodule.git submodule sync",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "update",
-      "--init",
-      "--recursive"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.submodule.git submodule update",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "rev-parse",
-      "HEAD"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.git rev-parse (2)",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.apply pigweed:1234",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LINK@gerrit@https://pigweed-review.googlesource.com/c/1234@@@",
-      "@@@STEP_LINK@gitiles@https://pigweed.googlesource.com/pigweed/pigweed/+/2d72510e447ab60a9728aeea2362d8be2cbd7789@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "https://pigweed.googlesource.com/pigweed/pigweed",
-      "2d72510e447ab60a9728aeea2362d8be2cbd7789",
-      "--no-recurse-submodules"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.apply pigweed:1234.git fetch patch",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "checkout",
-      "--force",
-      "-b",
-      "working",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.apply pigweed:1234.git checkout patch",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "rev-parse",
-      "HEAD"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.apply pigweed:1234.git rev-parse",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "update",
-      "--init",
-      "--recursive"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.apply pigweed:1234.git submodule update",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "status",
-      "--recursive"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.git submodule status",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.status",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@applied [_Change(number=1234, remote='https://pigweed.googlesource.com/pigweed/pigweed', ref='2d72510e447ab60a9728aeea2362d8be2cbd7789', rebase=False, branch='main', gerrit_name='pigweed', submitted=True, base='HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_', base_type='submitted_commit_hash')]\nnot applied []@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.git log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.git log.[START_DIR]/checkout",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.base",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@SET_BUILD_PROPERTY@got_revision@\"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\"@@@",
-      "@@@SET_BUILD_PROPERTY@got_revision_type@\"submitted_commit_hash\"@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0777",
-      "[START_DIR]/snapshot"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.mkdir",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "status",
-      "--recursive"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.submodule-status",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "submodule status filler text",
-      "[START_DIR]/snapshot/submodules.log"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.write submodule snapshot",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@submodules.log@submodule status filler text@@@",
-      "@@@STEP_LOG_END@submodules.log@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "",
-      "[START_DIR]/snapshot/git.log"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.write git log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_END@git.log@@@"
-    ]
-  },
-  {
-    "failure": {
-      "failure": {},
-      "humanReason": "no step or program properties"
-    },
-    "name": "$result"
-  }
-]
\ No newline at end of file
diff --git a/recipes/pw_presubmit.expected/pigweed.json b/recipes/pw_presubmit.expected/pigweed.json
deleted file mode 100644
index 302c7e3..0000000
--- a/recipes/pw_presubmit.expected/pigweed.json
+++ /dev/null
@@ -1,1702 +0,0 @@
-[
-  {
-    "cmd": [],
-    "name": "checkout pigweed",
-    "~followup_annotations": [
-      "@@@STEP_LINK@applied pigweed:1234@https://pigweed-review.googlesource.com/c/1234@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.change data",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.change data.process gitiles commit",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.change data.process gitiles commit.ensure gerrit",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "RECIPE_MODULE[fuchsia::gerrit]/resources/tool_manifest.json",
-      "/path/to/tmp/json"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.change data.process gitiles commit.ensure gerrit.read manifest",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@4@@@",
-      "@@@STEP_LOG_LINE@tool_manifest.json@{@@@",
-      "@@@STEP_LOG_LINE@tool_manifest.json@  \"path\": \"path/to/gerrit\",@@@",
-      "@@@STEP_LOG_LINE@tool_manifest.json@  \"version\": \"version:pinned-version\"@@@",
-      "@@@STEP_LOG_LINE@tool_manifest.json@}@@@",
-      "@@@STEP_LOG_END@tool_manifest.json@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.change data.process gitiles commit.ensure gerrit.install path/to/gerrit",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@4@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0777",
-      "[CACHE]/cipd/path/to/gerrit/version%3Apinned-version"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.change data.process gitiles commit.ensure gerrit.install path/to/gerrit.ensure package directory",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@5@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "cipd",
-      "ensure",
-      "-root",
-      "[CACHE]/cipd/path/to/gerrit/version%3Apinned-version",
-      "-ensure-file",
-      "path/to/gerrit version:pinned-version",
-      "-max-threads",
-      "0",
-      "-json-output",
-      "/path/to/tmp/json"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.change data.process gitiles commit.ensure gerrit.install path/to/gerrit.ensure_installed",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@5@@@",
-      "@@@STEP_LOG_LINE@json.output@{@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\", @@@",
-      "@@@STEP_LOG_LINE@json.output@        \"package\": \"path/to/gerrit\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      }@@@",
-      "@@@STEP_LOG_LINE@json.output@    ]@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@}@@@",
-      "@@@STEP_LOG_END@json.output@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "[CACHE]/cipd/path/to/gerrit/version%3Apinned-version/gerrit",
-      "change-query",
-      "-host",
-      "https://pigweed-review.googlesource.com",
-      "-input",
-      "{\"params\": {\"q\": \"commit:2d72510e447ab60a9728aeea2362d8be2cbd7789\"}}",
-      "-output",
-      "/path/to/tmp/json"
-    ],
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.change data.process gitiles commit.number",
-    "timeout": 30,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@",
-      "@@@STEP_LOG_LINE@json.output@[@@@",
-      "@@@STEP_LOG_LINE@json.output@  {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"_number\": \"1234\", @@@",
-      "@@@STEP_LOG_LINE@json.output@    \"branch\": \"main\"@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@]@@@",
-      "@@@STEP_LOG_END@json.output@@@",
-      "@@@STEP_LOG_LINE@json.input@{@@@",
-      "@@@STEP_LOG_LINE@json.input@  \"params\": {@@@",
-      "@@@STEP_LOG_LINE@json.input@    \"q\": \"commit:2d72510e447ab60a9728aeea2362d8be2cbd7789\"@@@",
-      "@@@STEP_LOG_LINE@json.input@  }@@@",
-      "@@@STEP_LOG_LINE@json.input@}@@@",
-      "@@@STEP_LOG_END@json.input@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.change data.changes",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.change data.changes.pigweed:1234",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@",
-      "@@@STEP_SUMMARY_TEXT@_Change(number=1234, remote='https://pigweed.googlesource.com/pigweed/pigweed', ref='2d72510e447ab60a9728aeea2362d8be2cbd7789', rebase=False, branch='main', gerrit_name='pigweed', submitted=True, base=None, base_type=None)@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0777",
-      "[START_DIR]/checkout"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.makedirs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "init"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.git init",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "remote",
-      "add",
-      "origin",
-      "https://pigweed.googlesource.com/pigweed/pigweed"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.git remote",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.set fetch.uriprotocols",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "",
-      "[CACHE]/git/.GUARD_FILE"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.cache.write guard file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@",
-      "@@@STEP_LOG_END@.GUARD_FILE@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0777",
-      "[CACHE]/git/pigweed.googlesource.com-pigweed-pigweed"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.cache.makedirs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "init",
-      "--bare"
-    ],
-    "cwd": "[CACHE]/git/pigweed.googlesource.com-pigweed-pigweed",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.cache.git init",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "remote.origin.url",
-      "https://pigweed.googlesource.com/pigweed/pigweed"
-    ],
-    "cwd": "[CACHE]/git/pigweed.googlesource.com-pigweed-pigweed",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.cache.remote set-url",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[CACHE]/git/pigweed.googlesource.com-pigweed-pigweed",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.cache.set fetch.uriprotocols",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "--replace-all",
-      "remote.origin.fetch",
-      "+refs/heads/*:refs/heads/*",
-      "\\+refs/heads/\\*:.*"
-    ],
-    "cwd": "[CACHE]/git/pigweed.googlesource.com-pigweed-pigweed",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.cache.replace fetch configs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--prune",
-      "--tags",
-      "origin"
-    ],
-    "cwd": "[CACHE]/git/pigweed.googlesource.com-pigweed-pigweed",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.cache.git fetch",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0777",
-      "[START_DIR]/checkout/.git/objects/info"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.cache.makedirs object/info",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "[CACHE]/git/pigweed.googlesource.com-pigweed-pigweed/objects\n",
-      "[START_DIR]/checkout/.git/objects/info/alternates"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.cache.alternates",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@",
-      "@@@STEP_LOG_LINE@alternates@[CACHE]/git/pigweed.googlesource.com-pigweed-pigweed/objects@@@",
-      "@@@STEP_LOG_END@alternates@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "remove",
-      "[CACHE]/git/.GUARD_FILE"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.cache.remove guard file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--tags",
-      "origin",
-      "main",
-      "--recurse-submodules"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.git fetch",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "checkout",
-      "-f",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.git checkout",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "rev-parse",
-      "HEAD"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.git rev-parse",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-d",
-      "-x"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.git clean",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.submodule",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "sync"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.submodule.git submodule sync",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "update",
-      "--init",
-      "--recursive"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.submodule.git submodule update",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "rev-parse",
-      "HEAD"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.git rev-parse (2)",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.apply pigweed:1234",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LINK@gerrit@https://pigweed-review.googlesource.com/c/1234@@@",
-      "@@@STEP_LINK@gitiles@https://pigweed.googlesource.com/pigweed/pigweed/+/2d72510e447ab60a9728aeea2362d8be2cbd7789@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "https://pigweed.googlesource.com/pigweed/pigweed",
-      "2d72510e447ab60a9728aeea2362d8be2cbd7789",
-      "--no-recurse-submodules"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.apply pigweed:1234.git fetch patch",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "checkout",
-      "--force",
-      "-b",
-      "working",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.apply pigweed:1234.git checkout patch",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "rev-parse",
-      "HEAD"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.apply pigweed:1234.git rev-parse",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "update",
-      "--init",
-      "--recursive"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.apply pigweed:1234.git submodule update",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "status",
-      "--recursive"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.git submodule status",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.status",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@applied [_Change(number=1234, remote='https://pigweed.googlesource.com/pigweed/pigweed', ref='2d72510e447ab60a9728aeea2362d8be2cbd7789', rebase=False, branch='main', gerrit_name='pigweed', submitted=True, base='HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_', base_type='submitted_commit_hash')]\nnot applied []@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.git log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.git log.[START_DIR]/checkout",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.base",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@SET_BUILD_PROPERTY@got_revision@\"HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_\"@@@",
-      "@@@SET_BUILD_PROPERTY@got_revision_type@\"submitted_commit_hash\"@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0777",
-      "[START_DIR]/snapshot"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.mkdir",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "status",
-      "--recursive"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.submodule-status",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "submodule status filler text",
-      "[START_DIR]/snapshot/submodules.log"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.write submodule snapshot",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@submodules.log@submodule status filler text@@@",
-      "@@@STEP_LOG_END@submodules.log@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "",
-      "[START_DIR]/snapshot/git.log"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.write git log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_END@git.log@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "environment"
-  },
-  {
-    "cmd": [],
-    "name": "get steps from programs"
-  },
-  {
-    "cmd": [
-      "foo",
-      "--directory",
-      "[START_DIR]/checkout",
-      "--loglevel",
-      "debug",
-      "presubmit",
-      "--package-root",
-      "[CACHE]",
-      "--output-directory",
-      "[START_DIR]/presubmit",
-      "--program",
-      "full",
-      "--only-list-steps"
-    ],
-    "env": {
-      "BUILDBUCKET_ID": "8945511751514863184",
-      "BUILDBUCKET_NAME": "project:ci:builder",
-      "BUILD_NUMBER": "0",
-      "GOCACHE": "[CACHE]/go",
-      "PIP_CACHE_DIR": "[CACHE]/pip",
-      "PW_ENVIRONMENT_NO_ERROR_ON_UNRECOGNIZED": "1",
-      "PW_ENVSETUP_DISABLE_SPINNER": "1",
-      "PW_PRESUBMIT_DISABLE_SUBPROCESS_CAPTURE": "1",
-      "PW_PROJECT_ROOT": "[START_DIR]/checkout",
-      "PW_ROOT": "[START_DIR]/checkout",
-      "TEST_TMPDIR": "[CACHE]/bazel"
-    },
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "get steps from programs.full",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "full_0"
-  },
-  {
-    "cmd": [
-      "foo",
-      "--directory",
-      "[START_DIR]/checkout",
-      "--loglevel",
-      "debug",
-      "presubmit",
-      "--package-root",
-      "[CACHE]",
-      "--output-directory",
-      "[START_DIR]/presubmit",
-      "--step",
-      "full_0"
-    ],
-    "env": {
-      "BUILDBUCKET_ID": "8945511751514863184",
-      "BUILDBUCKET_NAME": "project:ci:builder",
-      "BUILD_NUMBER": "0",
-      "GOCACHE": "[CACHE]/go",
-      "PIP_CACHE_DIR": "[CACHE]/pip",
-      "PW_ENVIRONMENT_NO_ERROR_ON_UNRECOGNIZED": "1",
-      "PW_ENVSETUP_DISABLE_SPINNER": "1",
-      "PW_PRESUBMIT_DISABLE_SUBPROCESS_CAPTURE": "1",
-      "PW_PROJECT_ROOT": "[START_DIR]/checkout",
-      "PW_ROOT": "[START_DIR]/checkout",
-      "TEST_TMPDIR": "[CACHE]/bazel"
-    },
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "full_0.run",
-    "timeout": 30,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0777",
-      "[START_DIR]/presubmit/full_0/export"
-    ],
-    "env": {
-      "BUILDBUCKET_ID": "8945511751514863184",
-      "BUILDBUCKET_NAME": "project:ci:builder",
-      "BUILD_NUMBER": "0",
-      "GOCACHE": "[CACHE]/go",
-      "PIP_CACHE_DIR": "[CACHE]/pip",
-      "PW_ENVIRONMENT_NO_ERROR_ON_UNRECOGNIZED": "1",
-      "PW_ENVSETUP_DISABLE_SPINNER": "1",
-      "PW_PRESUBMIT_DISABLE_SUBPROCESS_CAPTURE": "1",
-      "PW_PROJECT_ROOT": "[START_DIR]/checkout",
-      "PW_ROOT": "[START_DIR]/checkout",
-      "TEST_TMPDIR": "[CACHE]/bazel"
-    },
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "full_0.mkdir export",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "[START_DIR]/presubmit/full_0/ninja.log",
-      "/path/to/tmp/"
-    ],
-    "env": {
-      "BUILDBUCKET_ID": "8945511751514863184",
-      "BUILDBUCKET_NAME": "project:ci:builder",
-      "BUILD_NUMBER": "0",
-      "GOCACHE": "[CACHE]/go",
-      "PIP_CACHE_DIR": "[CACHE]/pip",
-      "PW_ENVIRONMENT_NO_ERROR_ON_UNRECOGNIZED": "1",
-      "PW_ENVSETUP_DISABLE_SPINNER": "1",
-      "PW_PRESUBMIT_DISABLE_SUBPROCESS_CAPTURE": "1",
-      "PW_PROJECT_ROOT": "[START_DIR]/checkout",
-      "PW_ROOT": "[START_DIR]/checkout",
-      "TEST_TMPDIR": "[CACHE]/bazel"
-    },
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "full_0.ninja.log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@ninja.log@2000 5000 0 medium 0@@@",
-      "@@@STEP_LOG_LINE@ninja.log@3000 8000 0 long 0@@@",
-      "@@@STEP_LOG_LINE@ninja.log@malformed line@@@",
-      "@@@STEP_LOG_LINE@ninja.log@4000 5000 0 short 0@@@",
-      "@@@STEP_LOG_LINE@ninja.log@5000 x 0 malformed-end-time 0@@@",
-      "@@@STEP_LOG_END@ninja.log@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "full_0.longest build steps",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "full_0.longest build steps.long",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@",
-      "@@@STEP_SUMMARY_TEXT@5.0s@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "full_0.longest build steps.medium",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@",
-      "@@@STEP_SUMMARY_TEXT@3.0s@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "full_0.longest build steps.short",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@",
-      "@@@STEP_SUMMARY_TEXT@1.0s@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "full_0.copy",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "[START_DIR]/presubmit/full_0/ninja.log",
-      "[START_DIR]/presubmit/full_0/export/ninja.log"
-    ],
-    "env": {
-      "BUILDBUCKET_ID": "8945511751514863184",
-      "BUILDBUCKET_NAME": "project:ci:builder",
-      "BUILD_NUMBER": "0",
-      "GOCACHE": "[CACHE]/go",
-      "PIP_CACHE_DIR": "[CACHE]/pip",
-      "PW_ENVIRONMENT_NO_ERROR_ON_UNRECOGNIZED": "1",
-      "PW_ENVSETUP_DISABLE_SPINNER": "1",
-      "PW_PRESUBMIT_DISABLE_SUBPROCESS_CAPTURE": "1",
-      "PW_PROJECT_ROOT": "[START_DIR]/checkout",
-      "PW_ROOT": "[START_DIR]/checkout",
-      "TEST_TMPDIR": "[CACHE]/bazel"
-    },
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "full_0.copy.ninja.log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "full_1"
-  },
-  {
-    "cmd": [
-      "foo",
-      "--directory",
-      "[START_DIR]/checkout",
-      "--loglevel",
-      "debug",
-      "presubmit",
-      "--package-root",
-      "[CACHE]",
-      "--output-directory",
-      "[START_DIR]/presubmit",
-      "--step",
-      "full_1"
-    ],
-    "env": {
-      "BUILDBUCKET_ID": "8945511751514863184",
-      "BUILDBUCKET_NAME": "project:ci:builder",
-      "BUILD_NUMBER": "0",
-      "GOCACHE": "[CACHE]/go",
-      "PIP_CACHE_DIR": "[CACHE]/pip",
-      "PW_ENVIRONMENT_NO_ERROR_ON_UNRECOGNIZED": "1",
-      "PW_ENVSETUP_DISABLE_SPINNER": "1",
-      "PW_PRESUBMIT_DISABLE_SUBPROCESS_CAPTURE": "1",
-      "PW_PROJECT_ROOT": "[START_DIR]/checkout",
-      "PW_ROOT": "[START_DIR]/checkout",
-      "TEST_TMPDIR": "[CACHE]/bazel"
-    },
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "full_1.run",
-    "timeout": 30,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0777",
-      "[START_DIR]/presubmit/full_1/export"
-    ],
-    "env": {
-      "BUILDBUCKET_ID": "8945511751514863184",
-      "BUILDBUCKET_NAME": "project:ci:builder",
-      "BUILD_NUMBER": "0",
-      "GOCACHE": "[CACHE]/go",
-      "PIP_CACHE_DIR": "[CACHE]/pip",
-      "PW_ENVIRONMENT_NO_ERROR_ON_UNRECOGNIZED": "1",
-      "PW_ENVSETUP_DISABLE_SPINNER": "1",
-      "PW_PRESUBMIT_DISABLE_SUBPROCESS_CAPTURE": "1",
-      "PW_PROJECT_ROOT": "[START_DIR]/checkout",
-      "PW_ROOT": "[START_DIR]/checkout",
-      "TEST_TMPDIR": "[CACHE]/bazel"
-    },
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "full_1.mkdir export",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "[START_DIR]/presubmit/full_1/ninja.log",
-      "/path/to/tmp/"
-    ],
-    "env": {
-      "BUILDBUCKET_ID": "8945511751514863184",
-      "BUILDBUCKET_NAME": "project:ci:builder",
-      "BUILD_NUMBER": "0",
-      "GOCACHE": "[CACHE]/go",
-      "PIP_CACHE_DIR": "[CACHE]/pip",
-      "PW_ENVIRONMENT_NO_ERROR_ON_UNRECOGNIZED": "1",
-      "PW_ENVSETUP_DISABLE_SPINNER": "1",
-      "PW_PRESUBMIT_DISABLE_SUBPROCESS_CAPTURE": "1",
-      "PW_PROJECT_ROOT": "[START_DIR]/checkout",
-      "PW_ROOT": "[START_DIR]/checkout",
-      "TEST_TMPDIR": "[CACHE]/bazel"
-    },
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "full_1.ninja.log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@ninja.log@2000 5000 0 medium 0@@@",
-      "@@@STEP_LOG_LINE@ninja.log@3000 8000 0 long 0@@@",
-      "@@@STEP_LOG_LINE@ninja.log@malformed line@@@",
-      "@@@STEP_LOG_LINE@ninja.log@4000 5000 0 short 0@@@",
-      "@@@STEP_LOG_LINE@ninja.log@5000 x 0 malformed-end-time 0@@@",
-      "@@@STEP_LOG_END@ninja.log@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "full_1.longest build steps",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "full_1.longest build steps.long",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@",
-      "@@@STEP_SUMMARY_TEXT@5.0s@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "full_1.longest build steps.medium",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@",
-      "@@@STEP_SUMMARY_TEXT@3.0s@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "full_1.longest build steps.short",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@",
-      "@@@STEP_SUMMARY_TEXT@1.0s@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "full_1.copy",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "[START_DIR]/presubmit/full_1/ninja.log",
-      "[START_DIR]/presubmit/full_1/export/ninja.log"
-    ],
-    "env": {
-      "BUILDBUCKET_ID": "8945511751514863184",
-      "BUILDBUCKET_NAME": "project:ci:builder",
-      "BUILD_NUMBER": "0",
-      "GOCACHE": "[CACHE]/go",
-      "PIP_CACHE_DIR": "[CACHE]/pip",
-      "PW_ENVIRONMENT_NO_ERROR_ON_UNRECOGNIZED": "1",
-      "PW_ENVSETUP_DISABLE_SPINNER": "1",
-      "PW_PRESUBMIT_DISABLE_SUBPROCESS_CAPTURE": "1",
-      "PW_PROJECT_ROOT": "[START_DIR]/checkout",
-      "PW_ROOT": "[START_DIR]/checkout",
-      "TEST_TMPDIR": "[CACHE]/bazel"
-    },
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "full_1.copy.ninja.log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "binary sizes full_0"
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "[START_DIR]/presubmit/full_0/export/binary_sizes.json",
-      "/path/to/tmp/"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "binary sizes full_0.read",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@binary_sizes.json@{@@@",
-      "@@@STEP_LOG_LINE@binary_sizes.json@  \"target\": 12345,@@@",
-      "@@@STEP_LOG_LINE@binary_sizes.json@  \"target.budget\": 12346@@@",
-      "@@@STEP_LOG_LINE@binary_sizes.json@}@@@",
-      "@@@STEP_LOG_END@binary_sizes.json@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "binary sizes full_1"
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "[START_DIR]/presubmit/full_1/export/binary_sizes.json",
-      "/path/to/tmp/"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "binary sizes full_1.read",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@binary_sizes.json@{@@@",
-      "@@@STEP_LOG_LINE@binary_sizes.json@  \"target\": 12345,@@@",
-      "@@@STEP_LOG_LINE@binary_sizes.json@  \"target.budget\": 12346@@@",
-      "@@@STEP_LOG_LINE@binary_sizes.json@}@@@",
-      "@@@STEP_LOG_END@binary_sizes.json@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "binary sizes",
-    "~followup_annotations": [
-      "@@@SET_BUILD_PROPERTY@binary_sizes@{\"full_0.target\": 12345, \"full_0.target.budget\": 12346, \"full_1.target\": 12345, \"full_1.target.budget\": 12346}@@@"
-    ]
-  },
-  {
-    "name": "$result"
-  }
-]
\ No newline at end of file
diff --git a/recipes/pw_presubmit.expected/repo.json b/recipes/pw_presubmit.expected/repo.json
deleted file mode 100644
index 96c7a5d..0000000
--- a/recipes/pw_presubmit.expected/repo.json
+++ /dev/null
@@ -1,1270 +0,0 @@
-[
-  {
-    "cmd": [],
-    "name": "checkout pigweed",
-    "~followup_annotations": [
-      "@@@STEP_LINK@applied pigweed:1234@https://pigweed-review.googlesource.com/c/1234@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.change data",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.change data.process gitiles commit",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.change data.process gitiles commit.ensure gerrit",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "RECIPE_MODULE[fuchsia::gerrit]/resources/tool_manifest.json",
-      "/path/to/tmp/json"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.change data.process gitiles commit.ensure gerrit.read manifest",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@4@@@",
-      "@@@STEP_LOG_LINE@tool_manifest.json@{@@@",
-      "@@@STEP_LOG_LINE@tool_manifest.json@  \"path\": \"path/to/gerrit\",@@@",
-      "@@@STEP_LOG_LINE@tool_manifest.json@  \"version\": \"version:pinned-version\"@@@",
-      "@@@STEP_LOG_LINE@tool_manifest.json@}@@@",
-      "@@@STEP_LOG_END@tool_manifest.json@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.change data.process gitiles commit.ensure gerrit.install path/to/gerrit",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@4@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0777",
-      "[CACHE]/cipd/path/to/gerrit/version%3Apinned-version"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.change data.process gitiles commit.ensure gerrit.install path/to/gerrit.ensure package directory",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@5@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "cipd",
-      "ensure",
-      "-root",
-      "[CACHE]/cipd/path/to/gerrit/version%3Apinned-version",
-      "-ensure-file",
-      "path/to/gerrit version:pinned-version",
-      "-max-threads",
-      "0",
-      "-json-output",
-      "/path/to/tmp/json"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.change data.process gitiles commit.ensure gerrit.install path/to/gerrit.ensure_installed",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@5@@@",
-      "@@@STEP_LOG_LINE@json.output@{@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\", @@@",
-      "@@@STEP_LOG_LINE@json.output@        \"package\": \"path/to/gerrit\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      }@@@",
-      "@@@STEP_LOG_LINE@json.output@    ]@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@}@@@",
-      "@@@STEP_LOG_END@json.output@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "[CACHE]/cipd/path/to/gerrit/version%3Apinned-version/gerrit",
-      "change-query",
-      "-host",
-      "https://pigweed-review.googlesource.com",
-      "-input",
-      "{\"params\": {\"q\": \"commit:2d72510e447ab60a9728aeea2362d8be2cbd7789\"}}",
-      "-output",
-      "/path/to/tmp/json"
-    ],
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.change data.process gitiles commit.number",
-    "timeout": 30,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@",
-      "@@@STEP_LOG_LINE@json.output@[@@@",
-      "@@@STEP_LOG_LINE@json.output@  {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"_number\": \"1234\", @@@",
-      "@@@STEP_LOG_LINE@json.output@    \"branch\": \"main\"@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@]@@@",
-      "@@@STEP_LOG_END@json.output@@@",
-      "@@@STEP_LOG_LINE@json.input@{@@@",
-      "@@@STEP_LOG_LINE@json.input@  \"params\": {@@@",
-      "@@@STEP_LOG_LINE@json.input@    \"q\": \"commit:2d72510e447ab60a9728aeea2362d8be2cbd7789\"@@@",
-      "@@@STEP_LOG_LINE@json.input@  }@@@",
-      "@@@STEP_LOG_LINE@json.input@}@@@",
-      "@@@STEP_LOG_END@json.input@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.change data.changes",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.change data.changes.pigweed:1234",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@",
-      "@@@STEP_SUMMARY_TEXT@_Change(number=1234, remote='https://pigweed.googlesource.com/pigweed/manifest', ref='2d72510e447ab60a9728aeea2362d8be2cbd7789', rebase=False, branch='main', gerrit_name='pigweed', submitted=True, base=None, base_type=None)@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0777",
-      "[START_DIR]/checkout"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.mkdir checkout",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "RECIPE_MODULE[pigweed::repo]/resources/repo",
-      "init",
-      "--manifest-url",
-      "https://pigweed.googlesource.com/pigweed/manifest",
-      "--groups",
-      "all",
-      "--manifest-branch",
-      "main",
-      "--manifest-name",
-      "default.xml"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.repo init",
-    "timeout": 20,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "find",
-      ".repo/",
-      "-type",
-      "f",
-      "-name",
-      "*.lock",
-      "-print",
-      "-delete"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.clear repo locks",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "RECIPE_MODULE[pigweed::repo]/resources/repo",
-      "forall",
-      "--ignore-missing",
-      "-j",
-      "32",
-      "-c",
-      "find",
-      ".git/",
-      "-type",
-      "f",
-      "-name",
-      "*.lock",
-      "-print",
-      "-delete"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.clear git locks",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.apply pigweed:1234",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LINK@gerrit@https://pigweed-review.googlesource.com/c/1234@@@",
-      "@@@STEP_LINK@gitiles@https://pigweed.googlesource.com/pigweed/manifest/+/2d72510e447ab60a9728aeea2362d8be2cbd7789@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "https://pigweed.googlesource.com/pigweed/manifest",
-      "2d72510e447ab60a9728aeea2362d8be2cbd7789",
-      "--no-recurse-submodules"
-    ],
-    "cwd": "[START_DIR]/checkout/.repo/manifests",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.apply pigweed:1234.git fetch patch",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "checkout",
-      "--force",
-      "-b",
-      "working",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[START_DIR]/checkout/.repo/manifests",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.apply pigweed:1234.git checkout patch",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "rev-parse",
-      "HEAD"
-    ],
-    "cwd": "[START_DIR]/checkout/.repo/manifests",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.apply pigweed:1234.git rev-parse",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "update",
-      "--init",
-      "--recursive"
-    ],
-    "cwd": "[START_DIR]/checkout/.repo/manifests",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.apply pigweed:1234.git submodule update",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "branch",
-      "--set-upstream-to=origin/main"
-    ],
-    "cwd": "[START_DIR]/checkout/.repo/manifests",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.apply pigweed:1234.git branch",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.read manifest",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@raw@<?xml version=\"1.0\" encoding=\"UTF-8\"?>@@@",
-      "@@@STEP_LOG_LINE@raw@<manifest>@@@",
-      "@@@STEP_LOG_LINE@raw@  <remote@@@",
-      "@@@STEP_LOG_LINE@raw@    name=\"default_remote\"@@@",
-      "@@@STEP_LOG_LINE@raw@    fetch=\"sso://default\"@@@",
-      "@@@STEP_LOG_LINE@raw@    />@@@",
-      "@@@STEP_LOG_LINE@raw@@@@",
-      "@@@STEP_LOG_LINE@raw@  <remote@@@",
-      "@@@STEP_LOG_LINE@raw@    name=\"pigweed_remote\"@@@",
-      "@@@STEP_LOG_LINE@raw@    revision=\"main\"@@@",
-      "@@@STEP_LOG_LINE@raw@    fetch=\"..\"@@@",
-      "@@@STEP_LOG_LINE@raw@    review=\"https://pigweed.googlesource.com\"@@@",
-      "@@@STEP_LOG_LINE@raw@    />@@@",
-      "@@@STEP_LOG_LINE@raw@@@@",
-      "@@@STEP_LOG_LINE@raw@  <remote@@@",
-      "@@@STEP_LOG_LINE@raw@    name=\"pigweed-internal_remote\"@@@",
-      "@@@STEP_LOG_LINE@raw@    revision=\"main\"@@@",
-      "@@@STEP_LOG_LINE@raw@    fetch=\"https://pigweed-internal.googlesource.com\"@@@",
-      "@@@STEP_LOG_LINE@raw@    review=\"https://pigweed-internal.googlesource.com\"@@@",
-      "@@@STEP_LOG_LINE@raw@    />@@@",
-      "@@@STEP_LOG_LINE@raw@@@@",
-      "@@@STEP_LOG_LINE@raw@  <remote@@@",
-      "@@@STEP_LOG_LINE@raw@    name=\"prefixed\"@@@",
-      "@@@STEP_LOG_LINE@raw@    fetch=\"https://foo.googlesource.com/prefix\"@@@",
-      "@@@STEP_LOG_LINE@raw@    review=\"https://foo.googlesource.com/prefix\"@@@",
-      "@@@STEP_LOG_LINE@raw@    />@@@",
-      "@@@STEP_LOG_LINE@raw@@@@",
-      "@@@STEP_LOG_LINE@raw@  <default@@@",
-      "@@@STEP_LOG_LINE@raw@    remote=\"default_remote\"@@@",
-      "@@@STEP_LOG_LINE@raw@    revision=\"main\"@@@",
-      "@@@STEP_LOG_LINE@raw@    />@@@",
-      "@@@STEP_LOG_LINE@raw@@@@",
-      "@@@STEP_LOG_LINE@raw@  <project@@@",
-      "@@@STEP_LOG_LINE@raw@    name=\"default_name\"@@@",
-      "@@@STEP_LOG_LINE@raw@    path=\"default_path\"@@@",
-      "@@@STEP_LOG_LINE@raw@    />@@@",
-      "@@@STEP_LOG_LINE@raw@@@@",
-      "@@@STEP_LOG_LINE@raw@  <project@@@",
-      "@@@STEP_LOG_LINE@raw@    name=\"pigweed_name\"@@@",
-      "@@@STEP_LOG_LINE@raw@    path=\"pigweed_path\"@@@",
-      "@@@STEP_LOG_LINE@raw@    remote=\"pigweed_remote\"@@@",
-      "@@@STEP_LOG_LINE@raw@    revision=\"main\"@@@",
-      "@@@STEP_LOG_LINE@raw@    />@@@",
-      "@@@STEP_LOG_LINE@raw@@@@",
-      "@@@STEP_LOG_LINE@raw@  <project@@@",
-      "@@@STEP_LOG_LINE@raw@    name=\"pigweed-internal_name\"@@@",
-      "@@@STEP_LOG_LINE@raw@    path=\"pigweed-internal_path\"@@@",
-      "@@@STEP_LOG_LINE@raw@    remote=\"pigweed-internal_remote\"@@@",
-      "@@@STEP_LOG_LINE@raw@    />@@@",
-      "@@@STEP_LOG_LINE@raw@@@@",
-      "@@@STEP_LOG_LINE@raw@  <project@@@",
-      "@@@STEP_LOG_LINE@raw@    name=\"pinned\"@@@",
-      "@@@STEP_LOG_LINE@raw@    path=\"pinned\"@@@",
-      "@@@STEP_LOG_LINE@raw@    remote=\"pigweed_remote\"@@@",
-      "@@@STEP_LOG_LINE@raw@    revision=\"0123456789012345678901234567890123456789\"@@@",
-      "@@@STEP_LOG_LINE@raw@    upstream=\"main\"@@@",
-      "@@@STEP_LOG_LINE@raw@    />@@@",
-      "@@@STEP_LOG_LINE@raw@@@@",
-      "@@@STEP_LOG_LINE@raw@  <project@@@",
-      "@@@STEP_LOG_LINE@raw@    name=\"suffix\"@@@",
-      "@@@STEP_LOG_LINE@raw@    path=\"prefix/suffix\"@@@",
-      "@@@STEP_LOG_LINE@raw@    remote=\"prefixed\"@@@",
-      "@@@STEP_LOG_LINE@raw@    />@@@",
-      "@@@STEP_LOG_LINE@raw@</manifest>@@@",
-      "@@@STEP_LOG_END@raw@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "[START_DIR]/checkout/.repo/manifests/default.xml",
-      "/path/to/tmp/"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.read manifest.read file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@",
-      "@@@STEP_LOG_LINE@default.xml@<?xml version=\"1.0\" encoding=\"UTF-8\"?>@@@",
-      "@@@STEP_LOG_LINE@default.xml@<manifest>@@@",
-      "@@@STEP_LOG_LINE@default.xml@  <remote@@@",
-      "@@@STEP_LOG_LINE@default.xml@    name=\"default_remote\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    fetch=\"sso://default\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    />@@@",
-      "@@@STEP_LOG_LINE@default.xml@@@@",
-      "@@@STEP_LOG_LINE@default.xml@  <remote@@@",
-      "@@@STEP_LOG_LINE@default.xml@    name=\"pigweed_remote\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    revision=\"main\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    fetch=\"..\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    review=\"https://pigweed.googlesource.com\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    />@@@",
-      "@@@STEP_LOG_LINE@default.xml@@@@",
-      "@@@STEP_LOG_LINE@default.xml@  <remote@@@",
-      "@@@STEP_LOG_LINE@default.xml@    name=\"pigweed-internal_remote\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    revision=\"main\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    fetch=\"https://pigweed-internal.googlesource.com\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    review=\"https://pigweed-internal.googlesource.com\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    />@@@",
-      "@@@STEP_LOG_LINE@default.xml@@@@",
-      "@@@STEP_LOG_LINE@default.xml@  <remote@@@",
-      "@@@STEP_LOG_LINE@default.xml@    name=\"prefixed\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    fetch=\"https://foo.googlesource.com/prefix\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    review=\"https://foo.googlesource.com/prefix\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    />@@@",
-      "@@@STEP_LOG_LINE@default.xml@@@@",
-      "@@@STEP_LOG_LINE@default.xml@  <default@@@",
-      "@@@STEP_LOG_LINE@default.xml@    remote=\"default_remote\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    revision=\"main\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    />@@@",
-      "@@@STEP_LOG_LINE@default.xml@@@@",
-      "@@@STEP_LOG_LINE@default.xml@  <project@@@",
-      "@@@STEP_LOG_LINE@default.xml@    name=\"default_name\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    path=\"default_path\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    />@@@",
-      "@@@STEP_LOG_LINE@default.xml@@@@",
-      "@@@STEP_LOG_LINE@default.xml@  <project@@@",
-      "@@@STEP_LOG_LINE@default.xml@    name=\"pigweed_name\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    path=\"pigweed_path\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    remote=\"pigweed_remote\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    revision=\"main\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    />@@@",
-      "@@@STEP_LOG_LINE@default.xml@@@@",
-      "@@@STEP_LOG_LINE@default.xml@  <project@@@",
-      "@@@STEP_LOG_LINE@default.xml@    name=\"pigweed-internal_name\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    path=\"pigweed-internal_path\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    remote=\"pigweed-internal_remote\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    />@@@",
-      "@@@STEP_LOG_LINE@default.xml@@@@",
-      "@@@STEP_LOG_LINE@default.xml@  <project@@@",
-      "@@@STEP_LOG_LINE@default.xml@    name=\"pinned\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    path=\"pinned\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    remote=\"pigweed_remote\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    revision=\"0123456789012345678901234567890123456789\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    upstream=\"main\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    />@@@",
-      "@@@STEP_LOG_LINE@default.xml@@@@",
-      "@@@STEP_LOG_LINE@default.xml@  <project@@@",
-      "@@@STEP_LOG_LINE@default.xml@    name=\"suffix\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    path=\"prefix/suffix\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    remote=\"prefixed\"@@@",
-      "@@@STEP_LOG_LINE@default.xml@    />@@@",
-      "@@@STEP_LOG_LINE@default.xml@</manifest>@@@",
-      "@@@STEP_LOG_END@default.xml@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "{\"projects\": [{\"name\": \"default_name\", \"path\": \"default_path\", \"remote\": \"default_remote\", \"revision\": \"main\", \"upstream\": \"main\", \"url\": \"https://default.googlesource.com/default_name\"}, {\"name\": \"pigweed_name\", \"path\": \"pigweed_path\", \"remote\": \"pigweed_remote\", \"revision\": \"main\", \"upstream\": \"main\", \"url\": \"https://pigweed.googlesource.com/pigweed_name\"}, {\"name\": \"pigweed-internal_name\", \"path\": \"pigweed-internal_path\", \"remote\": \"pigweed-internal_remote\", \"revision\": \"main\", \"upstream\": \"main\", \"url\": \"https://pigweed-internal.googlesource.com/pigweed-internal_name\"}, {\"name\": \"pinned\", \"path\": \"pinned\", \"remote\": \"pigweed_remote\", \"revision\": \"0123456789012345678901234567890123456789\", \"upstream\": \"main\", \"url\": \"https://pigweed.googlesource.com/pinned\"}, {\"name\": \"suffix\", \"path\": \"prefix/suffix\", \"remote\": \"prefixed\", \"revision\": \"main\", \"upstream\": \"main\", \"url\": \"https://foo.googlesource.com/prefix/suffix\"}], \"remotes\": {\"default_remote\": {\"alias\": null, \"fetch\": {\"https\": \"https://default.googlesource.com\", \"url\": \"sso://default\"}, \"name\": \"default_remote\", \"review\": null, \"revision\": null}, \"pigweed-internal_remote\": {\"alias\": null, \"fetch\": {\"https\": \"https://pigweed-internal.googlesource.com\", \"url\": \"https://pigweed-internal.googlesource.com\"}, \"name\": \"pigweed-internal_remote\", \"review\": \"https://pigweed-internal.googlesource.com\", \"revision\": \"main\"}, \"pigweed_remote\": {\"alias\": null, \"fetch\": {\"https\": \"https://pigweed.googlesource.com\", \"url\": \"https://pigweed.googlesource.com\"}, \"name\": \"pigweed_remote\", \"review\": \"https://pigweed.googlesource.com\", \"revision\": \"main\"}, \"prefixed\": {\"alias\": null, \"fetch\": {\"https\": \"https://foo.googlesource.com/prefix\", \"url\": \"https://foo.googlesource.com/prefix\"}, \"name\": \"prefixed\", \"review\": \"https://foo.googlesource.com/prefix\", \"revision\": null}}}",
-      "[START_DIR]/manifest.json"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.read manifest.manifest json",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@",
-      "@@@STEP_LOG_LINE@manifest.json@{\"projects\": [{\"name\": \"default_name\", \"path\": \"default_path\", \"remote\": \"default_remote\", \"revision\": \"main\", \"upstream\": \"main\", \"url\": \"https://default.googlesource.com/default_name\"}, {\"name\": \"pigweed_name\", \"path\": \"pigweed_path\", \"remote\": \"pigweed_remote\", \"revision\": \"main\", \"upstream\": \"main\", \"url\": \"https://pigweed.googlesource.com/pigweed_name\"}, {\"name\": \"pigweed-internal_name\", \"path\": \"pigweed-internal_path\", \"remote\": \"pigweed-internal_remote\", \"revision\": \"main\", \"upstream\": \"main\", \"url\": \"https://pigweed-internal.googlesource.com/pigweed-internal_name\"}, {\"name\": \"pinned\", \"path\": \"pinned\", \"remote\": \"pigweed_remote\", \"revision\": \"0123456789012345678901234567890123456789\", \"upstream\": \"main\", \"url\": \"https://pigweed.googlesource.com/pinned\"}, {\"name\": \"suffix\", \"path\": \"prefix/suffix\", \"remote\": \"prefixed\", \"revision\": \"main\", \"upstream\": \"main\", \"url\": \"https://foo.googlesource.com/prefix/suffix\"}], \"remotes\": {\"default_remote\": {\"alias\": null, \"fetch\": {\"https\": \"https://default.googlesource.com\", \"url\": \"sso://default\"}, \"name\": \"default_remote\", \"review\": null, \"revision\": null}, \"pigweed-internal_remote\": {\"alias\": null, \"fetch\": {\"https\": \"https://pigweed-internal.googlesource.com\", \"url\": \"https://pigweed-internal.googlesource.com\"}, \"name\": \"pigweed-internal_remote\", \"review\": \"https://pigweed-internal.googlesource.com\", \"revision\": \"main\"}, \"pigweed_remote\": {\"alias\": null, \"fetch\": {\"https\": \"https://pigweed.googlesource.com\", \"url\": \"https://pigweed.googlesource.com\"}, \"name\": \"pigweed_remote\", \"review\": \"https://pigweed.googlesource.com\", \"revision\": \"main\"}, \"prefixed\": {\"alias\": null, \"fetch\": {\"https\": \"https://foo.googlesource.com/prefix\", \"url\": \"https://foo.googlesource.com/prefix\"}, \"name\": \"prefixed\", \"review\": \"https://foo.googlesource.com/prefix\", \"revision\": null}}}@@@",
-      "@@@STEP_LOG_END@manifest.json@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "--global",
-      "--add",
-      "url.https://default.googlesource.com/a.insteadof",
-      "sso://default"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.git insteadof sso://default",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "RECIPE_MODULE[pigweed::repo]/resources/repo",
-      "sync",
-      "--force-sync",
-      "--current-branch",
-      "--jobs",
-      "2"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.repo sync",
-    "timeout": 120,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "RECIPE_MODULE[pigweed::repo]/resources/repo",
-      "start",
-      "base",
-      "--all"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.repo start",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.status",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@applied [_Change(number=1234, remote='https://pigweed.googlesource.com/pigweed/manifest', ref='2d72510e447ab60a9728aeea2362d8be2cbd7789', rebase=False, branch='main', gerrit_name='pigweed', submitted=True, base='HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_HEAD_', base_type='submitted_commit_hash')]\nnot applied []@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout pigweed.root",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@root=[START_DIR]/checkout\nself._root=[START_DIR]/checkout\n@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "listdir",
-      "[START_DIR]/checkout"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.ls",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_END@listdir@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0777",
-      "[START_DIR]/snapshot"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.mkdir",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "RECIPE_MODULE[pigweed::repo]/resources/repo",
-      "manifest",
-      "-r"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.repo manifest",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@raw_io.output_text@<manifest></manifest>@@@",
-      "@@@STEP_LOG_END@raw_io.output_text@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "<manifest></manifest>",
-      "[START_DIR]/snapshot/manifest.xml"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.write manifest.xml",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@manifest.xml@<manifest></manifest>@@@",
-      "@@@STEP_LOG_END@manifest.xml@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "status",
-      "--recursive"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.submodule-status",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "submodule status filler text",
-      "[START_DIR]/snapshot/submodules.log"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.write submodule snapshot",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@submodules.log@submodule status filler text@@@",
-      "@@@STEP_LOG_END@submodules.log@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/checkout",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "",
-      "[START_DIR]/snapshot/git.log"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout pigweed.write git log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_END@git.log@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "environment"
-  },
-  {
-    "cmd": [],
-    "name": "step"
-  },
-  {
-    "cmd": [
-      "python",
-      "-m",
-      "pw_cli",
-      "--directory",
-      "[START_DIR]/checkout",
-      "--loglevel",
-      "debug",
-      "presubmit",
-      "--package-root",
-      "[CACHE]",
-      "--output-directory",
-      "[START_DIR]/presubmit",
-      "--base",
-      "HEAD~1",
-      "--step",
-      "step"
-    ],
-    "env": {
-      "BUILDBUCKET_ID": "8945511751514863184",
-      "BUILDBUCKET_NAME": "project:ci:builder",
-      "BUILD_NUMBER": "0",
-      "GOCACHE": "[CACHE]/go",
-      "PIP_CACHE_DIR": "[CACHE]/pip",
-      "PW_ENVIRONMENT_NO_ERROR_ON_UNRECOGNIZED": "1",
-      "PW_ENVSETUP_DISABLE_SPINNER": "1",
-      "PW_PRESUBMIT_DISABLE_SUBPROCESS_CAPTURE": "1",
-      "PW_PROJECT_ROOT": "[START_DIR]/checkout",
-      "PW_ROOT": "[START_DIR]/checkout",
-      "TEST_TMPDIR": "[CACHE]/bazel"
-    },
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "step.run",
-    "timeout": 30,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0777",
-      "[START_DIR]/presubmit/step/export"
-    ],
-    "env": {
-      "BUILDBUCKET_ID": "8945511751514863184",
-      "BUILDBUCKET_NAME": "project:ci:builder",
-      "BUILD_NUMBER": "0",
-      "GOCACHE": "[CACHE]/go",
-      "PIP_CACHE_DIR": "[CACHE]/pip",
-      "PW_ENVIRONMENT_NO_ERROR_ON_UNRECOGNIZED": "1",
-      "PW_ENVSETUP_DISABLE_SPINNER": "1",
-      "PW_PRESUBMIT_DISABLE_SUBPROCESS_CAPTURE": "1",
-      "PW_PROJECT_ROOT": "[START_DIR]/checkout",
-      "PW_ROOT": "[START_DIR]/checkout",
-      "TEST_TMPDIR": "[CACHE]/bazel"
-    },
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "step.mkdir export",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "[START_DIR]/presubmit/step/ninja.log",
-      "/path/to/tmp/"
-    ],
-    "env": {
-      "BUILDBUCKET_ID": "8945511751514863184",
-      "BUILDBUCKET_NAME": "project:ci:builder",
-      "BUILD_NUMBER": "0",
-      "GOCACHE": "[CACHE]/go",
-      "PIP_CACHE_DIR": "[CACHE]/pip",
-      "PW_ENVIRONMENT_NO_ERROR_ON_UNRECOGNIZED": "1",
-      "PW_ENVSETUP_DISABLE_SPINNER": "1",
-      "PW_PRESUBMIT_DISABLE_SUBPROCESS_CAPTURE": "1",
-      "PW_PROJECT_ROOT": "[START_DIR]/checkout",
-      "PW_ROOT": "[START_DIR]/checkout",
-      "TEST_TMPDIR": "[CACHE]/bazel"
-    },
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "step.ninja.log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@ninja.log@2000 5000 0 medium 0@@@",
-      "@@@STEP_LOG_LINE@ninja.log@3000 8000 0 long 0@@@",
-      "@@@STEP_LOG_LINE@ninja.log@malformed line@@@",
-      "@@@STEP_LOG_LINE@ninja.log@4000 5000 0 short 0@@@",
-      "@@@STEP_LOG_LINE@ninja.log@5000 x 0 malformed-end-time 0@@@",
-      "@@@STEP_LOG_END@ninja.log@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "step.longest build steps",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "step.longest build steps.long",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@",
-      "@@@STEP_SUMMARY_TEXT@5.0s@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "step.longest build steps.medium",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@",
-      "@@@STEP_SUMMARY_TEXT@3.0s@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "step.longest build steps.short",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@",
-      "@@@STEP_SUMMARY_TEXT@1.0s@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "step.copy",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "[START_DIR]/presubmit/step/ninja.log",
-      "[START_DIR]/presubmit/step/export/ninja.log"
-    ],
-    "env": {
-      "BUILDBUCKET_ID": "8945511751514863184",
-      "BUILDBUCKET_NAME": "project:ci:builder",
-      "BUILD_NUMBER": "0",
-      "GOCACHE": "[CACHE]/go",
-      "PIP_CACHE_DIR": "[CACHE]/pip",
-      "PW_ENVIRONMENT_NO_ERROR_ON_UNRECOGNIZED": "1",
-      "PW_ENVSETUP_DISABLE_SPINNER": "1",
-      "PW_PRESUBMIT_DISABLE_SUBPROCESS_CAPTURE": "1",
-      "PW_PROJECT_ROOT": "[START_DIR]/checkout",
-      "PW_ROOT": "[START_DIR]/checkout",
-      "TEST_TMPDIR": "[CACHE]/bazel"
-    },
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "step.copy.ninja.log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "binary sizes step"
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "[START_DIR]/presubmit/step/export/binary_sizes.json",
-      "/path/to/tmp/"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "binary sizes step.read",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@binary_sizes.json@{@@@",
-      "@@@STEP_LOG_LINE@binary_sizes.json@  \"target\": 12345,@@@",
-      "@@@STEP_LOG_LINE@binary_sizes.json@  \"target.budget\": 12346@@@",
-      "@@@STEP_LOG_LINE@binary_sizes.json@}@@@",
-      "@@@STEP_LOG_END@binary_sizes.json@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "binary sizes",
-    "~followup_annotations": [
-      "@@@SET_BUILD_PROPERTY@binary_sizes@{\"target\": 12345, \"target.budget\": 12346}@@@"
-    ]
-  },
-  {
-    "name": "$result"
-  }
-]
\ No newline at end of file
diff --git a/recipes/pw_presubmit.expected/sign-nobuildid.json b/recipes/pw_presubmit.expected/sign-nobuildid.json
index 1580b1d..9076be8 100644
--- a/recipes/pw_presubmit.expected/sign-nobuildid.json
+++ b/recipes/pw_presubmit.expected/sign-nobuildid.json
@@ -1167,7 +1167,7 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "release.run",
+    "name": "release.release",
     "timeout": 30,
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@"
@@ -1560,36 +1560,6 @@
       "--json-output",
       "/path/to/tmp/json",
       "listdir",
-      "[START_DIR]/presubmit"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "upload.ls presubmit",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@listdir@[START_DIR]/presubmit/release@@@",
-      "@@@STEP_LOG_END@listdir@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "listdir",
       "[START_DIR]/presubmit/release/export",
       "--recursive"
     ],
diff --git a/recipes/pw_presubmit.expected/sign.json b/recipes/pw_presubmit.expected/sign.json
index 7c86575..1bc1f1b 100644
--- a/recipes/pw_presubmit.expected/sign.json
+++ b/recipes/pw_presubmit.expected/sign.json
@@ -1167,7 +1167,7 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "release.run",
+    "name": "release.release",
     "timeout": 30,
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@"
@@ -1560,36 +1560,6 @@
       "--json-output",
       "/path/to/tmp/json",
       "listdir",
-      "[START_DIR]/presubmit"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "upload.ls presubmit",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@listdir@[START_DIR]/presubmit/release@@@",
-      "@@@STEP_LOG_END@listdir@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "listdir",
       "[START_DIR]/presubmit/release/export",
       "--recursive"
     ],
diff --git a/recipes/pw_presubmit.expected/step.json b/recipes/pw_presubmit.expected/step.json
index c260f34..bbd65b5 100644
--- a/recipes/pw_presubmit.expected/step.json
+++ b/recipes/pw_presubmit.expected/step.json
@@ -1491,7 +1491,7 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "step1.run",
+    "name": "step1.step1",
     "timeout": 40.0,
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@"
@@ -1714,7 +1714,7 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "step2.run",
+    "name": "step2.step2",
     "timeout": 30,
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@"
@@ -2145,37 +2145,6 @@
       "--json-output",
       "/path/to/tmp/json",
       "listdir",
-      "[START_DIR]/presubmit"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:try"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "upload.ls presubmit",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@listdir@[START_DIR]/presubmit/step1@@@",
-      "@@@STEP_LOG_LINE@listdir@[START_DIR]/presubmit/step2@@@",
-      "@@@STEP_LOG_END@listdir@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "listdir",
       "[START_DIR]/presubmit/step1/export",
       "--recursive"
     ],
diff --git a/recipes/pw_presubmit.proto b/recipes/pw_presubmit.proto
index 7165534..15b16b8 100644
--- a/recipes/pw_presubmit.proto
+++ b/recipes/pw_presubmit.proto
@@ -19,28 +19,9 @@
 package recipes.pigweed.pw_presubmit;
 
 message InputProperties {
-  // Command name in case it's changed by a dependent project. Default if unset
-  // is "pw".
-  string command_name = 1;
-
-  // Step to run from 'pw presubmit'. See 'pw presubmit --help' for options.
-  // Default is to run all steps.
-  repeated string step = 2;
-
   // Bucket to upload build to. Default is to not upload.
-  string gcs_bucket = 3;
+  string gcs_bucket = 1;
 
   // File extensions to sign. (E.g., ".out", ".sign-me", ...)
-  repeated string extensions_to_sign = 4;
-
-  // Program to run from 'pw presubmit'. See 'pw presubmit --help' for options.
-  // Default is to let 'pw presubmit' run its default program.
-  repeated string program = 5;
-
-  // Only run this check against changed files.
-  bool only_on_changed_files = 6;
-
-  // Subdirectory of the build directory to upload to GCS. Required to upload
-  // build artifacts.
-  string export_dir_name = 7;
+  repeated string extensions_to_sign = 2;
 }
diff --git a/recipes/pw_presubmit.py b/recipes/pw_presubmit.py
index aab4d80..4fe254e 100644
--- a/recipes/pw_presubmit.py
+++ b/recipes/pw_presubmit.py
@@ -22,11 +22,10 @@
 DEPS = [
     'fuchsia/gsutil',
     'fuchsia/status_check',
-    'pigweed/build',
     'pigweed/checkout',
     'pigweed/environment',
+    'pigweed/pw_presubmit',
     'pigweed/util',
-    'recipe_engine/buildbucket',
     'recipe_engine/file',
     'recipe_engine/futures',
     'recipe_engine/json',
@@ -50,30 +49,6 @@
 RELEASE_PUBKEY_FILENAME = 'publickey.pem'
 
 
-def _step_timeout(api):
-    # Amount of time elapsed in the run.
-    elapsed_time = api.time.time() - api.buildbucket.build.start_time.seconds
-
-    # Amount of time before build times out.
-    time_remaining = (
-        api.buildbucket.build.execution_timeout.seconds - elapsed_time
-    )
-
-    # Give a buffer before build times out and kill this step then. This should
-    # give enough time to read any logfiles and maybe upload to logdog/GCS
-    # before the build times out.
-    step_timeout = time_remaining - 60
-
-    # If the timeout would be negative or very small set it to 30 seconds. We
-    # likely won't have enough information to debug these steps, but in case
-    # they're fast there's no reason to kill them much before the build is
-    # terminated.
-    if step_timeout < 30:
-        step_timeout = 30
-
-    return step_timeout
-
-
 def _try_sign_archive(api, archive_path, name):
     args = [
         '--archive-file',
@@ -91,110 +66,45 @@
 
 def RunSteps(api, props):
     """Run Pigweed presubmit checks."""
-    # TODO(mohrr) Transition to passing a list in through properties.
-    command_name = props.command_name or 'python -m pw_cli'
     gcs_bucket = props.gcs_bucket
 
     api.checkout()
     root = api.checkout.root
 
-    if not props.step and not props.program:
-        raise api.step.StepFailure('no step or program properties')
-
     api.environment.init(root)
 
-    presubmit_dir = api.path['start_dir'].join('presubmit')
-
-    prefix = command_name.split()
-    prefix += [
-        '--directory',
-        root,
-        '--loglevel',
-        'debug',
-        'presubmit',
-        '--package-root',
-        api.path['cache'],
-        '--output-directory',
-        presubmit_dir,
-    ]
-
-    if props.only_on_changed_files:
-        prefix.extend(('--base', 'HEAD~1'))
-
     with api.environment():
-        steps = []
-        steps.extend(props.step)
-
-        if props.program:
-            with api.step.nest('get steps from programs'):
-                for program in props.program:
-                    # To get step_test_data line to pass pylint.
-                    raw_io_stream_output = (
-                        api.raw_io.test_api.stream_output_text
-                    )
-
-                    program_steps = (
-                        api.step(
-                            program,
-                            prefix
-                            + ['--program', program, '--only-list-steps'],
-                            stdout=api.raw_io.output_text(),
-                            step_test_data=lambda: raw_io_stream_output(
-                                '{0}_0\n{0}_1\n'.format(program),
-                            ),
-                        )
-                        .stdout.strip()
-                        .splitlines()
-                    )
-                    steps.extend(x for x in program_steps if x not in steps)
-
-        if not steps:
-            raise api.step.StepFailure('no steps to execute')
+        api.pw_presubmit.init(root)
 
         with api.step.defer_results():
-            for step in steps:
-                with api.step.nest(step) as pres:
-                    api.step(
-                        'run',
-                        prefix + ['--step', step],
-                        timeout=_step_timeout(api),
-                    )
+            for step in api.pw_presubmit.steps():
+                api.pw_presubmit.run(step)
 
-                    build_dir = presubmit_dir.join(step)
-                    export_dir = None
-                    if props.export_dir_name:
-                        export_dir = build_dir.join(props.export_dir_name)
-                        api.file.ensure_directory(
-                            'mkdir {}'.format(props.export_dir_name),
-                            export_dir,
-                        )
+    binary_size_data = {}
+    for step in api.pw_presubmit.steps():
+        if not step.export_dir:
+            continue  # pragma: no cover
 
-                    api.build.save_logs(build_dir, export_dir)
+        binary_sizes_json = step.export_dir.join('binary_sizes.json')
 
-    if props.export_dir_name:
-        binary_size_data = {}
-        for step in steps:
-            binary_sizes_json = presubmit_dir.join(
-                step, props.export_dir_name, 'binary_sizes.json'
-            )
+        api.path.mock_add_file(binary_sizes_json)
+        if api.path.isfile(binary_sizes_json):
+            with api.step.nest('binary sizes {}'.format(step.name)):
+                binary_size_data[step.name] = api.file.read_json(
+                    'read',
+                    binary_sizes_json,
+                    test_data={'target': 12345, 'target.budget': 12346},
+                )
 
-            api.path.mock_add_file(binary_sizes_json)
-            if api.path.isfile(binary_sizes_json):
-                with api.step.nest('binary sizes {}'.format(step)):
-                    binary_size_data[step] = api.file.read_json(
-                        'read',
-                        binary_sizes_json,
-                        test_data={'target': 12345, 'target.budget': 12346},
-                    )
+    binary_sizes = {}
+    if len(binary_size_data) == 1:
+        _, binary_sizes = binary_size_data.popitem()
+    elif len(binary_size_data) > 1:
+        for step_name, values in binary_size_data.items():
+            for name, size in values.items():
+                binary_sizes['{}.{}'.format(step_name, name)] = size
 
-        binary_sizes = {}
-        if len(binary_size_data) == 1:
-            _, binary_sizes = binary_size_data.popitem()
-        elif len(binary_size_data) > 1:
-            for step, values in binary_size_data.items():
-                for name, size in values.items():
-                    binary_sizes['{}.{}'.format(step, name)] = size
-
+    if binary_sizes:
         with api.step.nest('binary sizes') as pres:
             pres.properties['binary_sizes'] = binary_sizes
 
@@ -203,7 +113,7 @@
 
         with api.step.nest('upload') as pres:
             with api.environment():
-                command = command_name.split()
+                command = api.pw_presubmit.command_name.split()
                 command.extend(['--directory', root, 'build-id'])
                 step_data = api.step(
                     'get build id',
@@ -243,60 +153,62 @@
                 )
             )
 
-            if props.export_dir_name:
-                for step_dir in api.file.listdir(
-                    'ls presubmit', presubmit_dir, test_data=props.step,
+            for step in api.pw_presubmit.steps():
+                if not api.pw_presubmit.export_dir_name:
+                    continue  # pragma: no cover
+
+                step_dir = api.pw_presubmit.root.join(step.name)
+                export_dir = step_dir.join(api.pw_presubmit.export_dir_name)
+
+                # In testing this will never be true because of the
+                # mock_add_file() call for binary_sizes.json.
+                if not api.path.exists(export_dir):
+                    continue  # pragma: no cover
+
+                for entry in api.file.listdir(
+                    'ls {}/{}'.format(
+                        step.name, api.pw_presubmit.export_dir_name,
+                    ),
+                    export_dir,
+                    recursive=True,
                 ):
-                    step_name = api.path.basename(step_dir)
-                    export_dir = step_dir.join(props.export_dir_name)
-                    # In testing this will never be true because of the
-                    # mock_add_file() call for binary_sizes.json.
-                    if not api.path.exists(export_dir):
-                        continue  # pragma: no cover
+                    metadata = None
 
-                    for entry in api.file.listdir(
-                        'ls {}/{}'.format(step_name, props.export_dir_name),
-                        export_dir,
-                        recursive=True,
-                    ):
-                        metadata = None
-
-                        ext = api.path.splitext(entry)[1]
-                        if ext in props.extensions_to_sign:
-                            signature = _try_sign_archive(
-                                api,
-                                entry,
-                                name=api.path.relpath(entry, presubmit_dir),
-                            )
-                            if signature:
-                                metadata = {
-                                    "x-goog-meta-signature": signature,
-                                }
-                                if not uploaded_public_key:
-                                    futures.append(
-                                        api.futures.spawn(
-                                            api.gsutil.upload_namespaced_file,
-                                            source=RELEASE_PUBKEY_PATH,
-                                            bucket=gcs_bucket,
-                                            subpath=RELEASE_PUBKEY_FILENAME,
-                                            namespace=namespace,
-                                        )
-                                    )
-                                    uploaded_public_key = True
-
-                        futures.append(
-                            api.futures.spawn(
-                                api.gsutil.upload_namespaced_file,
-                                source=entry,
-                                bucket=gcs_bucket,
-                                subpath='{}/{}'.format(
-                                    step_name,
-                                    api.path.relpath(entry, export_dir),
-                                ),
-                                namespace=namespace,
-                                metadata=metadata,
-                            )
+                    ext = api.path.splitext(entry)[1]
+                    if ext in props.extensions_to_sign:
+                        signature = _try_sign_archive(
+                            api,
+                            entry,
+                            name=api.path.relpath(entry, api.pw_presubmit.root),
                         )
+                        if signature:
+                            metadata = {
+                                "x-goog-meta-signature": signature,
+                            }
+                            if not uploaded_public_key:
+                                futures.append(
+                                    api.futures.spawn(
+                                        api.gsutil.upload_namespaced_file,
+                                        source=RELEASE_PUBKEY_PATH,
+                                        bucket=gcs_bucket,
+                                        subpath=RELEASE_PUBKEY_FILENAME,
+                                        namespace=namespace,
+                                    )
+                                )
+                                uploaded_public_key = True
+
+                    futures.append(
+                        api.futures.spawn(
+                            api.gsutil.upload_namespaced_file,
+                            source=entry,
+                            bucket=gcs_bucket,
+                            subpath='{}/{}'.format(
+                                step.name, api.path.relpath(entry, export_dir),
+                            ),
+                            namespace=namespace,
+                            metadata=metadata,
+                        )
+                    )
 
             # Need to wait for results but don't care about their values.
             _ = [f.result() for f in futures]
@@ -337,31 +249,15 @@
 
     def properties(**kwargs):
         new_kwargs = api.checkout.git_properties()
-        new_kwargs['export_dir_name'] = 'export'
-        new_kwargs.update(kwargs)
+        new_kwargs['$pigweed/pw_presubmit'] = {'export_dir_name': 'export'}
+        if 'gcs_bucket' in kwargs:
+            new_kwargs['gcs_bucket'] = kwargs.pop('gcs_bucket')
+        if 'extensions_to_sign' in kwargs:
+            new_kwargs['extensions_to_sign'] = kwargs.pop('extensions_to_sign')
+        new_kwargs['$pigweed/pw_presubmit'].update(kwargs)
         return api.properties(**new_kwargs)
 
     yield (
-        api.status_check.test('no-steps', status='failure')
-        + properties()
-        + api.checkout.ci_test_data()
-    )
-
-    yield (
-        api.status_check.test('empty-program', status='failure')
-        + properties(program=['empty'])
-        + api.step_data(
-            "get steps from programs.empty", stdout=api.raw_io.output_text(''),
-        )
-    )
-
-    yield (
-        api.status_check.test('pigweed')
-        + properties(command_name='foo', program=['full'])
-        + api.checkout.ci_test_data()
-    )
-
-    yield (
         api.status_check.test('step')
         + properties(step=['step1', 'step2'], gcs_bucket='bucket')
         + api.checkout.try_test_data(
@@ -374,18 +270,6 @@
         + api.time.step(20.0)
     )
 
-    manifest = 'https://pigweed.googlesource.com/pigweed/manifest'
-    yield (
-        api.status_check.test('repo')
-        + properties(
-            step=['step'],
-            only_on_changed_files=True,
-            **api.checkout.repo_properties(remote=manifest)
-        )
-        + api.checkout.ci_test_data(manifest)
-        + api.checkout.manifest_test_data(name='pigweed')
-    )
-
     yield (
         api.status_check.test('sign')
         + properties(