)]}'
{
  "commit": "7cb2dcf05e49611c458fe606305955e49984e526",
  "tree": "8d4bf2aabb65c18db50edb6cd68aee2119556442",
  "parents": [
    "cc1a29a9b846e48306b56b2bed37a1d6ac71b9c3"
  ],
  "author": {
    "name": "Steven Troxler",
    "email": "stroxler@meta.com",
    "time": "Tue Aug 25 11:47:13 2026 -0700"
  },
  "committer": {
    "name": "Facebook GitHub Bot",
    "email": "facebook-github-bot@users.noreply.github.com",
    "time": "Tue Aug 25 11:47:13 2026 -0700"
  },
  "message": "Replace the Buck stub tests with one shared harness\n\nSummary:\nThe torch and numpy stub packages each carried their own near-duplicate\n`run_pyrefly.py`, and the two had drifted: numpy could run Pyrefly out of Buck\nbut not from a release build, torch could do the reverse. Adding a third package\nfor jax would have meant a third copy and a third set of gaps. The runtime side\nhad the same problem from the other direction, with the Buck targets and the\nGitHub workflow building their environments in completely different ways, so a\ngreen run in one said little about the other.\n\nFactor the parts that do not vary between packages into `shape_testing.py`: a\n`Suite` describing a named group of test files, resolution of the Pyrefly binary\nand of the virtualenv, and the two runners. A package now supplies only its\n`suites.py` plus thin entry points, so jax will be additive rather than another\ncopy.\n\nDelete the Buck stub test targets rather than port them. They were a second,\ndivergent way to run the same checks, and two of them built torch from source to\ndo it. Everything now goes through one runner, so `test.py`, the internal\nSandcastle job and the GitHub job differ only in where the Pyrefly binary comes\nfrom; `--buck` selects it in an internal checkout. The stub `python_library` and\nsearch-path targets stay, because they are how internal tooling and the porting\nskills point Pyrefly at the stubs.\n\nSeparate bootstrapping from running, which is the main design constraint here.\n`bootstrap_venv.py` is the only thing that touches the network; the runners never\ncreate anything and fail with a message naming the fix instead. That matters\nbecause on a Meta machine the download needs fwdproxy, and a sandboxed agent\ncannot do it at all without being relaunched with `--secure-internet-mode`.\nKeeping the two apart means everything except bootstrap works offline, and the\none step that cannot is reported clearly rather than hanging. One virtualenv at\n`~/.tensor-shapes-venv` serves all the libraries, since the runtime tests only\nbuild arrays and read shapes.\n\nType checking needs no virtualenv at all: Pyrefly resolves the stubs through\n`--search-path` and never imports the real library. `run_tests.py --static-only`\nexposes that, and the missing-virtualenv error advertises it, because it is the\nusual mode when working on Pyrefly itself rather than on the stubs.\n\nPin the libraries, and pin them to CPU-only builds. These tests assert the shapes\nthe libraries actually produce, so an unpinned minor bump can turn a correct stub\nred. Shape checking never runs a kernel, so the CUDA stack is pure cost: the\nresulting virtualenv is 1.3G against 5.1G for a CUDA one.\n\nRun everything as a single job on both CI systems -- `fbcode//pyrefly:oss`\u0027s\nsibling `:tensor_shapes` internally, one set of steps on GitHub -- rather than\none job per library. The whole suite takes about 25 seconds, so splitting it\nwould cost more in scheduling than it catches. The internal job installs `uv`\nwhen the image does not provide it, the way the neighbouring continuous jobs\nbootstrap their own tooling.\n\nTwo behaviors are preserved deliberately. `GRADUAL_SHAPE_RUNTIME_TESTS` is now\nhonored by the shared runner: a test whose static shape is gradual may use plain\nruntime assertions, because `assert_shape` still demands an exact static shape.\nAnd the two numpy-behavior tests from the deleted `numpy_runtime_test` wrapper\nmove into `test/test_indexing.py`, where they keep asserting that NumPy rejects\nfloat array indices and mismatched paired index lengths at runtime. Pyrefly does\nnot reject either statically, so they carry no inline error expectation and a\ncomment records the gap.\n\nOn GitHub, type checking runs on the whole matrix and only the runtime half is\nUbuntu-only. Type checking needs no virtualenv, and the runners carry\nWindows-specific interpreter and `.exe` path handling that nothing else would\nexercise, so restricting it would leave that code untested on the only platform\nit exists for. The runtime half is genuinely platform independent, so installing\ntorch and jax three times to assert the same shapes would be waste.\n\nDifferential Revision: D117306584\n\n\n",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "94975d9de91c4b45137701f054a03e636844d28a",
      "old_mode": 33188,
      "old_path": ".claude/skills/add-torch-shapes-example/SKILL.md",
      "new_id": "6d0fd909c6823531259a0a2d7b7f5df04396382d",
      "new_mode": 33188,
      "new_path": ".claude/skills/add-torch-shapes-example/SKILL.md"
    },
    {
      "type": "modify",
      "old_id": "29892fbff8bf7607bca059b1666b555e9775104a",
      "old_mode": 33188,
      "old_path": ".github/workflows/pyrefly.yml",
      "new_id": "d7d7cb5ff905279ef27530791be208592fce6b5c",
      "new_mode": 33188,
      "new_path": ".github/workflows/pyrefly.yml"
    },
    {
      "type": "modify",
      "old_id": "d340da6ebff97495447d943fc8018a089029d04a",
      "old_mode": 33188,
      "old_path": "TENSOR_SHAPES_CONTRIBUTING.md",
      "new_id": "2b6566e82ca1c9c99aab7a325a219094e6d7ddfe",
      "new_mode": 33188,
      "new_path": "TENSOR_SHAPES_CONTRIBUTING.md"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "3667cbe265b7bbb78b6fb7f54534ce072584e0cf",
      "new_mode": 33188,
      "new_path": "tensor-shapes/bootstrap_venv.py"
    },
    {
      "type": "modify",
      "old_id": "a951998e8444c8f21927bc1ce51f3012b42802d7",
      "old_mode": 33188,
      "old_path": "tensor-shapes/pyrefly-numpy-stubs/run_pyrefly.py",
      "new_id": "bc52468681001ae84bc5076bedfa58955641a162",
      "new_mode": 33188,
      "new_path": "tensor-shapes/pyrefly-numpy-stubs/run_pyrefly.py"
    },
    {
      "type": "modify",
      "old_id": "5b97bb9c71e736de1388e2c52030b2b48058ac23",
      "old_mode": 33188,
      "old_path": "tensor-shapes/pyrefly-numpy-stubs/run_runtime_tests.py",
      "new_id": "1fad34c16319e3bd8e47dff8a63d5367a6737502",
      "new_mode": 33188,
      "new_path": "tensor-shapes/pyrefly-numpy-stubs/run_runtime_tests.py"
    },
    {
      "type": "modify",
      "old_id": "b443f83ee83ce0e0e2dd51a84a4a0192df707988",
      "old_mode": 33188,
      "old_path": "tensor-shapes/pyrefly-numpy-stubs/suites.py",
      "new_id": "49c4f3af810489cf08e5c29f42c70a7199358616",
      "new_mode": 33188,
      "new_path": "tensor-shapes/pyrefly-numpy-stubs/suites.py"
    },
    {
      "type": "delete",
      "old_id": "84dd9330ca520e08eaa6a51c8f57137453bf99d3",
      "old_mode": 33188,
      "old_path": "tensor-shapes/pyrefly-numpy-stubs/test/runtime_tests/test_runtime.py",
      "new_id": "0000000000000000000000000000000000000000",
      "new_mode": 0,
      "new_path": "/dev/null"
    },
    {
      "type": "modify",
      "old_id": "d1843fc93833f30c7243917439f6bc19d11b865c",
      "old_mode": 33188,
      "old_path": "tensor-shapes/pyrefly-numpy-stubs/test/test_indexing.py",
      "new_id": "0c13e1c2501df2c8e8b3d62bffaa2654269bec92",
      "new_mode": 33188,
      "new_path": "tensor-shapes/pyrefly-numpy-stubs/test/test_indexing.py"
    },
    {
      "type": "modify",
      "old_id": "db2617b3bbcaa4767d7d916a907a60bef2122422",
      "old_mode": 33188,
      "old_path": "tensor-shapes/pyrefly-torch-stubs/run_pyrefly.py",
      "new_id": "285293ee34b08740f0cc4f5fc695a6571af43460",
      "new_mode": 33188,
      "new_path": "tensor-shapes/pyrefly-torch-stubs/run_pyrefly.py"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "6a6e7b3c80b10683735d14fa9e6bd6675ab44999",
      "new_mode": 33188,
      "new_path": "tensor-shapes/pyrefly-torch-stubs/suites.py"
    },
    {
      "type": "modify",
      "old_id": "babfd2c03cbf19cbcd3762748fb492be07aef683",
      "old_mode": 33261,
      "old_path": "tensor-shapes/run_all_shape_tests.py",
      "new_id": "0f5e1a7407bd85744309d41ac9252e01c769d920",
      "new_mode": 33261,
      "new_path": "tensor-shapes/run_all_shape_tests.py"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "0c063463a7802fb49058ed7431debccc7cf32f26",
      "new_mode": 33188,
      "new_path": "tensor-shapes/run_tests.py"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "eb00195efcce0b9b9b0b1d08e3cbd66a5503160f",
      "new_mode": 33188,
      "new_path": "tensor-shapes/shape_testing.py"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "3d46f48f713c2c651d4579d28b14928daba6f578",
      "new_mode": 33188,
      "new_path": "tensor-shapes/test-requirements.txt"
    },
    {
      "type": "modify",
      "old_id": "181c49a54fb9e0d78c0ac1930eaf014186a5a944",
      "old_mode": 33261,
      "old_path": "test.py",
      "new_id": "60d3f78fb35f4062b128e589fc558f7cf5a817ea",
      "new_mode": 33261,
      "new_path": "test.py"
    }
  ]
}
