anchor.diff:    }
   
     // Locate the builds we're interested in and map them to each commit. The
  -  // builds returned by the API are sorted with the newest first. Since bots
  +  // builds returned by the API are sorted with the newest first. Since builders
     // don't build back in time and always build the latest commit whenever they
     // can, the first time we see a commit, we know it's newer than all commits
  -  // we haven't seen yet. The insertion order into the botsForCommits map will
  -  // then sorted with the newest commit first.
  -  final builds = object["builds"];
  -  final botsForCommits = <String, Set<String>>{};
  +  // we haven't seen yet. The insertion order into the buildersForCommits map
  +  // will then sorted with the newest commit first.
  +  final builds = searchResult["builds"];
  +  if (builds == null) {
  +    print("No builds found");
  +    exit(1);
  +  }
  +  final buildersForCommits = <String, Set<String>>{};
     for (final build in builds) {
  -    final parameters = jsonDecode(build["parameters_json"]);
  -    final bot = parameters["builder_name"];
  -    if (bot.endsWith("-beta") ||
  -        bot.endsWith("-dev") ||
  -        bot.endsWith("-stable")) {
  +    final builder = build["builder"]?["builder"];
  +    if (builder is! String ||
  +        builder.endsWith("-beta") ||
  +        builder.endsWith("-dev") ||
  +        builder.endsWith("-stable")) {
         // Ignore the release builders. The -try builders aren't in the
         // bucket we're reading.
         continue;
       }
  -    if (globs.isNotEmpty && !globs.any((glob) => glob.matches(bot))) {
  -      // Filter way bots we're not interested in.
  +    if (globs.isNotEmpty && !globs.any((glob) => glob.matches(builder))) {
  +      // Filter way builders we're not interested in.
         continue;
       }
  -    final properties = parameters["properties"];
  -    final branch = properties["branch"];
  -    if (branch != null && branch != "refs/heads/${options['branch']}") {
  -      // Ignore bots that are building the wrong branch.
  +    final input = build["input"]?["gitilesCommit"];
  +    if (input == null) {
  +      // Ignore builds not triggered by a commit, e.g. fuzz-linux.
         continue;
       }
  -    final commit = properties["revision"];
  -    if (commit == null) {
  -      // Ignore bots that aren't commit based, e.g. fuzz-linux.
  +    final ref = input["ref"];
  +    if (ref != "refs/heads/${options['branch']}") {
  +      // Ignore builds on the wrong branch.
         continue;
       }
  -    final botsForCommit =
  -        botsForCommits.putIfAbsent(commit, () => new Set<String>());
  -    botsForCommit.add(bot);
  +    final commit = input["id"] as String;
  +    final buildersForCommit =
  +        buildersForCommits.putIfAbsent(commit, () => new Set<String>());
  +    buildersForCommit.add(builder);
     }
   
  -  if (botsForCommits.isEmpty) {
  -    print("Failed to locate any commits having run on the bots");
  +  if (buildersForCommits.isEmpty) {
  +    print("Failed to locate any commits having run on the builders");
       exitCode = 1;
       return;
     }
   
     int maxBots = 0;
  -  for (final commit in botsForCommits.keys) {
  -    maxBots = max(maxBots, botsForCommits[commit].length);
  +  for (final builders in buildersForCommits.values) {
  +    maxBots = max(maxBots, builders.length);
     }
   
  -  // List commits run on the most bots.
  -  for (final commit in botsForCommits.keys
  -      .where((commit) => botsForCommits[commit].length == maxBots)
  +  // List commits run on the most builders.
  +  for (final commit in buildersForCommits.keys
  +      .where((commit) => buildersForCommits[commit]!.length == maxBots)
         .take(count)) {
       print(commit);
     }
  
positive.code:   if (options["help"]) {
      print("""
  Usage: find_base_commit.dart [OPTION]...
  Find the newest commit that has a full set of results on the bots.
  
  The options are as follows:
  
  
negative.code: 
    int count = int.parse(options["count"]);
    final globs = new List<Glob>.from(
        options["builder"].map((String pattern) => new Glob(pattern)));
  
    // Download the most recent builds from buildbucket.
    const maxBuilds = 1000;
    final url = Uri.parse("https://cr-buildbucket.appspot.com"
        "/prpc/buildbucket.v2.Builds/SearchBuilds");
    const maxRetries = 3;
    const timeout = const Duration(seconds: 30);
    final query = jsonEncode({
      "predicate": {
        "builder": {"project": "dart", "bucket": "ci.sandbox"},
        "status": "ENDED_MASK"
      },
      "pageSize": maxBuilds,
      "fields": "builds.*.builder.builder,builds.*.input"
    });
    late Map<String, dynamic> searchResult;
    for (int i = 1; i <= maxRetries; i++) {
      try {
        final client = new HttpClient();
        final request = await client.postUrl(url).timeout(timeout)
          ..headers.contentType = ContentType.json
          ..headers.add(HttpHeaders.acceptHeader, ContentType.json)
          ..write(query);
        final response = await request.close().timeout(timeout);
        if (response.statusCode != 200) {
          print("Failed to search for builds: "
              "${response.statusCode}:${response.reasonPhrase}");
          exit(1);
        }
        const prefix = ")]}'";
        searchResult = await (response
            .cast<List<int>>()
            .transform(new Utf8Decoder())
            .map((event) =>
                event.startsWith(prefix) ? event.substring(prefix.length) : event)
            .transform(new JsonDecoder())
            .cast<Map<String, dynamic>>()
            .first
            .timeout(timeout));
        client.close();
        break;
      } on TimeoutException catch (e) {
        final inSeconds = e.duration?.inSeconds;
        stderr.writeln(
            "Attempt $i of $maxRetries timed out after $inSeconds seconds");
        if (i == maxRetries) {
  