)]}'
{
  "commit": "9eab6366c55aeffdec24eae7760b1ae562f7a510",
  "tree": "69943910ddf975960ef5b311e8d760483a0a5ebe",
  "parents": [
    "b4262ef9d46b23fcd9f73f43b17aecb7a644649d"
  ],
  "author": {
    "name": "Harry Terkelsen",
    "email": "1961493+harryterkelsen@users.noreply.github.com",
    "time": "Mon Oct 19 17:47:10 2026 +0000"
  },
  "committer": {
    "name": "GitHub",
    "email": "noreply@github.com",
    "time": "Mon Oct 19 17:47:10 2026 +0000"
  },
  "message": "Add web benchmark baseline comparison, ANSI summary table, and structured JSON helpers (#194609)\n\nAdds pure, unit-tested helpers in\n`dev/devicelab/lib/tasks/web_benchmarks_comparison.dart` that compare a\nweb benchmark run against a saved baseline and print the result as a\nterminal table. A follow-up PR uses them in a local benchmark CLI.\n\n- `compareResults` compares the `.average` metrics that appear in both\nthe current and the baseline `TaskResult.data` maps, sorted by key; all\nother keys are ignored. It computes each metric\u0027s percentage change and\nflags a regression when the change exceeds an optional\n`regressionThreshold`. Speedups are never regressions, and a metric that\nrises from zero has an infinite delta. Invalid thresholds throw\n`ArgumentError`, and compared values that are not finite, non-negative\nnumbers throw `FormatException`.\n- `formatAnsiSummaryTable` prints a `Metric` / `Baseline` / `Current` /\n`Delta` / `Status` table with a header and separator row, right-aligned\nnumbers, and an optionally ANSI-colored `PASS`/`FAIL` status.\n- Adds `kSmokeTestBenchmarks` to `web_benchmarks.dart`, the curated fast\nbenchmark set (`draw_rect`, `bench_card_infinite_scroll`) for the CLI\u0027s\n`--smoke-test` flag.\n- Adds unit tests in\n`dev/devicelab/test/tasks/web_benchmarks_test.dart`: a table-driven\nmatrix of delta and threshold cases (including zero baselines, no\nthreshold and a delta equal to the threshold), key selection, input\nvalidation, and an exact expected-table test.\n\nPart of https://github.com/flutter/flutter/issues/191316\n\n## Pre-launch Checklist\n\n- [x] I read the [Contributor Guide] and followed the process outlined\nthere for submitting PRs.\n- [x] I read the [AI contribution guidelines] and understand my\nresponsibilities, or I am not using AI tools.\n- [x] I read the [Tree Hygiene] wiki page, which explains my\nresponsibilities.\n- [x] I read and followed the [Flutter Style Guide], including [Features\nwe expect every widget to implement].\n- [x] I signed the [CLA].\n- [x] I listed at least one issue that this PR fixes in the description\nabove.\n- [x] I updated/added relevant in-code documentation (doc comments with\n`///`).\n- [x] If this PR introduces a new feature or capability, I created and\nlinked a website documentation issue or PR in [flutter/website] (or\nverified none is needed).\n- [x] I added new tests to check the change I am making, or this PR is\n[test-exempt].\n- [x] I followed the [breaking change policy] and added [Data Driven\nFixes] where supported.\n- [x] All existing and new tests are passing.\n\n\u003c!-- Links --\u003e\n[Contributor Guide]:\nhttps://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview\n[AI contribution guidelines]:\nhttps://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#ai-contribution-guidelines\n[Tree Hygiene]:\nhttps://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md\n[test-exempt]:\nhttps://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests\n[Flutter Style Guide]:\nhttps://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md\n[Features we expect every widget to implement]:\nhttps://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement\n[CLA]: https://cla.developers.google.com/\n[flutter/tests]: https://github.com/flutter/tests\n[flutter/website]: https://github.com/flutter/website\n[breaking change policy]:\nhttps://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes\n[Discord]:\nhttps://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md\n[Data Driven Fixes]:\nhttps://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "9fd70f51e1acdb23fecefc04e170d50bf423f670",
      "old_mode": 33188,
      "old_path": "dev/devicelab/lib/tasks/web_benchmarks.dart",
      "new_id": "1b7422a8e61d0bc8731a240d789fa1d150ac45ed",
      "new_mode": 33188,
      "new_path": "dev/devicelab/lib/tasks/web_benchmarks.dart"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "09f6706c9f45f0be1eec5bbad5490c4ae3ccddcd",
      "new_mode": 33188,
      "new_path": "dev/devicelab/lib/tasks/web_benchmarks_comparison.dart"
    },
    {
      "type": "modify",
      "old_id": "c19d13c053d936f7ccd133223a3ed57f5547d0c5",
      "old_mode": 33188,
      "old_path": "dev/devicelab/test/tasks/web_benchmarks_test.dart",
      "new_id": "1b8efe3d8d21a957822f7a7dd7c0c86890c91f9b",
      "new_mode": 33188,
      "new_path": "dev/devicelab/test/tasks/web_benchmarks_test.dart"
    }
  ]
}
