)]}'
{
  "commit": "ff35ee4a2073848cd2fe5b5b88a495a844b3c6e1",
  "tree": "fcc874e2e2ee0e309b4bbba89bbb96c15a19e588",
  "parents": [
    "809c0f5059f06b118bd86dba6e60bf52336aaf17"
  ],
  "author": {
    "name": "Albert Lloveras",
    "email": "albert.l@canva.com",
    "time": "Thu Sep 17 07:15:33 2026 +0000"
  },
  "committer": {
    "name": "GitHub",
    "email": "noreply@github.com",
    "time": "Thu Sep 17 07:15:33 2026 +0000"
  },
  "message": "fix(stamping): skip build data spawn when --stamp\u003dfalse (#4160)\n\n## Summary\n\n`PyWriteBuildData` is dirty on every build with a cold Skyframe when\noutputs are not downloaded. That is, once per `py_binary` and `py_test`\nin the build. When stamping is off, the output is a constant, so the\naction spawn is pure overhead.\n\n## Root Cause Analysis\n\nThe output is declared with\n`_py_builtins.declare_constant_metadata_file`. Constant metadata always\nreports itself as unchanged, so Bazel cannot validate it from the action\ncache. It stats the output on disk instead.\n\nUnder `--remote_download_outputs\u003dminimal` the output is not on disk. The\nstat fails and the action is dirty. It re-executes, hits the remote\ncache, is still not downloaded, and is dirty again on the next\ncold-server build. Setting `--remote_download_regex` to match the file\navoids this, at the cost of downloading it, which confirms the stat is\nthe trigger.\n\nThe use of a constant metadata file is justified (as per the comment in\nthe code). With stamping on, the action reads `volatile-status.txt`,\nwhich changes every build. The build data file is in the binary\u0027s\nrunfiles, so without it its consumers would invalidate on every build\ndue to timestamps.\n\nHowever, with stamping off, there is no volatile input. There is nothing\nto shield. Unfortunately, the current implementation keeps the\n_additional_ cost (constant metadata being always unchanged plus failed\n`stat` syscalls) for none of the benefits.\n\n## Change\n\nWhen `is_stamping_enabled(ctx)` is false, the content of the file is\nknown at analysis time:\n\n```\nTARGET \u003clabel\u003e\nSTAMPED FALSE\n```\n\nSo declare an ordinary output and write it with `ctx.actions.write`. No\nspawn, and no constant metadata output.\n\nNote this is broader than `--nostamp`. `is_stamping_enabled` is also\nfalse for the exec configuration and for `stamp \u003d 0`, so tool-config\nbinaries benefit from the fix even when `--stamp\u003dtrue` is set at the top\nlevel.\n\nThe stamped path is unchanged and keeps its constant metadata output.\n\n## Compatibility\n\nThe output is byte-identical. The label is written with `str(ctx.label)`\nto match `\"TARGET\": str(ctx.label)` in the spawn\u0027s env, which yields the\ncanonical `@@//pkg:target` form. `ctx.actions.args().add(ctx.label)`\nrenders the display form and drops the `@@`.\n\nAfter the change, the tests in `tests/build_data/build_data_test.py`\npass without any modifications.\n\n## Alternative considered\n\nKeeping the spawn and declaring an ordinary output would also fix the\ndirtiness. Writing at analysis time is lighter, since it needs no\nsubprocess.\n\n## Environment\n\nrules_python 2.2.0, Bazel 9.2.0, Linux. Reproduce with\n`--remote_download_outputs\u003dminimal` against a warm remote cache, then\n`bazel shutdown` and rebuild.",
  "tree_diff": [
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "5f87118bd16f792242af799467042bc45a7de790",
      "new_mode": 33188,
      "new_path": "news/4160.fixed.md"
    },
    {
      "type": "modify",
      "old_id": "f7386ee353789b4a86fbfbe0f29ab5858a78bb78",
      "old_mode": 33188,
      "old_path": "python/private/py_executable.bzl",
      "new_id": "62742d334cbbddabc9153f507e53efeb64afd9e6",
      "new_mode": 33188,
      "new_path": "python/private/py_executable.bzl"
    }
  ]
}
