)]}'
{
  "log": [
    {
      "commit": "1321aa43ce2bd5a4bef38c571f723882fe6b8520",
      "tree": "0d60cd56d273c75a499d61993dfa6e474ebd3c6c",
      "parents": [
        "5bec107f7329d8f72739cbbaaba7c92965f19ae4"
      ],
      "author": {
        "name": "Jia Chen",
        "email": "grievejia@meta.com",
        "time": "Fri Aug 28 10:34:32 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Fri Aug 28 10:34:32 2026 -0700"
      },
      "message": "Preserve parameter references in unopened files\n\nSummary:\nAn earlier change fixed incoming call hierarchy for files that the client did not open. It requested `Require::Everything` for every file that depends on the target module. This made the required ASTs available. However, the same helper also serves find references and find implementations. Those requests then performed full analysis on every dependent file.\n\nD117389890 (PR) limits that work. Incoming call hierarchy performs full analysis only on files that reference the target. Type hierarchy performs full analysis on its candidate files. Most find-reference requests and all find-implementation requests use only the retained index. This keeps incoming call hierarchy correct and makes common reference requests faster.\n\nD117389890 leaves one correctness problem. Parameter references do not use only the index. To find a keyword argument such as `greet(message\u003d\"Hello\")`, Pyrefly scans the caller AST. It also uses bindings to confirm that the keyword resolves to the selected parameter. An unopened file has neither at `Require::Indexing`. Find references therefore omits the keyword argument. Rename can change the parameter definition but leave `message\u003d` unchanged in the unopened caller.\n\nThis diff requests `Require::Everything` for all dependent files only when the selected definition is a parameter. Other definitions keep the index-only path from D117389890. This restores parameter references and rename without removing the main performance improvement.\n\nThis diff also removes a duplicate type-hierarchy request for `Require::Everything`. The caller already makes the same request before it reads the candidate files.\n\nThe tests cover parameter references and parameter rename in an unopened caller file. The call hierarchy test now has two unopened caller files. This verifies that one batch prepares every selected caller file.\n\nReviewed By: stroxler\n\nDifferential Revision: D117455220\n\nfbshipit-source-id: f8ba135ace020fbcd0e4ba9b0e7509773ba832be\n"
    },
    {
      "commit": "5bec107f7329d8f72739cbbaaba7c92965f19ae4",
      "tree": "6a5780d65751b6a69784846627cee1c724a0858e",
      "parents": [
        "449467e0396f038de07b9e40ffc51b11ff0f15ae"
      ],
      "author": {
        "name": "DarkNightForge",
        "email": "eashanbabber@gmail.com",
        "time": "Fri Aug 28 10:34:32 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Fri Aug 28 10:34:32 2026 -0700"
      },
      "message": "Scope the Require::Everything escalation to the requests that read ASTs, and add the #3636 regression test (#4643)\n\nSummary:\nFollow-up to https://github.com/facebook/pyrefly/issues/3637 (landed as `3c288a2`), measured against `origin/main` @ `8ec5070d2`.\n\nTwo things: the regression test https://github.com/facebook/pyrefly/issues/3636 still lacks, and a narrowing of where the\n`Require::Everything` escalation is paid.\n\n## 1. The regression test\n\n`3c288a2` is correct — I verified `test_incoming_call_hierarchy_unopened_caller_file` passes\nagainst unmodified `main`. But it landed as 4 additions / 3 deletions in one file with no test,\nso nothing holds the behaviour. `test_incoming_call_hierarchy_basic` opens *both* files, so it\ncannot catch https://github.com/facebook/pyrefly/issues/3636.\n\nThe new test opens only `callee.py` and runs with `IndexingMode::LazyBlocking`, so `caller.py`\nis reached through the index. Verified to fail against the code as it stood before `3c288a2`.\n\nd34db3ff — this is the test we discussed on https://github.com/facebook/pyrefly/issues/3637; the PR merged before I could add it there.\n\n## 2. Who pays for the escalation\n\n`3c288a2` moved the escalation into `compute_transitive_rdeps_for_definition_impl`, which is\nshared by four features. Only two of them ever read an AST:\n\n| consumer | reads an AST? |\n| --- | --- |\n| `callHierarchy/incomingCalls` | **yes** — `get_ast`, to attribute a call site to its enclosing function |\n| `typeHierarchy` subtypes | **yes** — `get_ast` + `get_solutions` + `get_bindings` |\n| `textDocument/references` | no — `local_references_from_definition` and `find_child_implementations_impl` are both index-backed |\n| `find_global_implementations_from_definition` | no — `solutions_index` only |\n\nSo `references`, much the hottest of the four, now runs a full check over every transitive rdep\nof the definition\u0027s module and retains their ASTs for data it never reads.\n\nThis PR moves the escalation to the two consumers that need it:\n\n- **call hierarchy** asks the index which rdeps actually reference the target, then escalates\n  only those. A file that never mentions the target costs nothing beyond the lookup. Ordering\n  matters: the pre-`3c288a2` code fetched the AST *before* checking for references. The\n  escalation is batched into one `run` — doing it per file from inside the walk leaves every\n  file after the first still without an AST.\n- **type hierarchy** escalates its own deduped candidates, so its behaviour is exactly what\n  `main` does today.\n\n`references` and `implementations` stop paying entirely.\n\n## Measurements\n\nThis answers the perf question yangdanny97 raised on https://github.com/facebook/pyrefly/issues/3637 in June.\n\nRelease builds, a 209-file Python project (the same one I profiled on https://github.com/facebook/pyrefly/issues/3637, since grown from\n189), LSP driven programmatically opening only the file it queries. **A fresh server per cold rep**, median of 3; the timed request is the first one that\nserver receives. RSS delta is sampled immediately before and after that single request, so it is\nwhat the request itself retained. Result counts in parentheses are ground truth and were\nidentical on both builds. The three positions are the same ones I profiled on https://github.com/facebook/pyrefly/issues/3637.\n\n| | refs (82) | refs (36) | `incomingCalls` (32) |\n| --- | --- | --- | --- |\n| `main` @ `8ec5070d2` — cold | 65.4 ms | 31.5 ms | 31.6 ms |\n| this PR — cold | **3.4 ms** | **1.9 ms** | **26.8 ms** |\n| `main` — RSS retained by the one request | 81 MB | 15 MB | 16 MB |\n| this PR — RSS retained | **2 MB** | **1 MB** | **7 MB** |\n| `main` — server peak RSS | 396 MB | 329 MB | 316 MB |\n| this PR — server peak RSS | **281 MB** | **281 MB** | **291 MB** |\n\nThe whole table was run twice on a quiet machine; every figure reproduced within 1%\n(e.g. refs (82) cold 65.4 / 65.5 ms on `main`, 3.4 / 3.4 ms here).\n\nA note on methodology, because it changes the answer: the profile I posted on https://github.com/facebook/pyrefly/issues/3637 used a\n**median of 5 warm reps**. Escalation to `Require::Everything` is a one-time state transition\nthat the transaction retains, so reps 2..5 measure the already-escalated steady state and a warm\nmedian structurally hides the cost being argued about. That profile was not evidence that the\nescalation is cheap. Hence the fresh-server-per-rep harness here.\n\n## Test suite\n\n`cargo test --lib --no-fail-fast` on this branch: **8,093 passed / 0 failed / 4 ignored** in the\n`pyrefly` crate, 8,828 passed and 0 failed across all 13 test binaries. The 4 ignored are\npre-existing. Result counts from the probes above were identical to `main` on every case\n(82 / 36 / 32), so this is a cost change, not a behaviour change.\n\n## What this does not do\n\nNothing tests the *cost* property. If the escalation is re-broadened later, the tests stay green\nand only the numbers change. I did not find a good way to assert it at this layer; suggestions\nwelcome.\n\nPull Request resolved: https://github.com/facebook/pyrefly/pull/4643\n\nReviewed By: stroxler\n\nDifferential Revision: D117389890\n\nfbshipit-source-id: e1ef862413d9efe7b926b545b3f9b396713a6c85\n"
    },
    {
      "commit": "449467e0396f038de07b9e40ffc51b11ff0f15ae",
      "tree": "14ae45bb20ef3fb1529abf78499a0bcbabf1aed8",
      "parents": [
        "0c2f22b48ea696a22beab6853595378882d0e423"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Fri Aug 28 10:13:30 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Fri Aug 28 10:13:30 2026 -0700"
      },
      "message": "Bump the PyPI publishing action version\n\nSummary:\nHatchling now emits Core Metadata 2.5, and the pinned v1.13 publishing action bundles Twine 6.x, which rejects that metadata version during artifact validation. This is what blocked the shape stub uploads for 1.3.0.dev2 and 1.3.0.dev3. The main `pyrefly` package is unaffected because it is built with maturin, but its workflow uses the same action pin, so it is worth moving both in lockstep.\n\nPoint both publishing workflows at `gh-action-pypi-publish` v1.14.2. That release exists essentially to bump the action\u0027s bundled Twine to 7.0.0, which is the version that adds Core Metadata 2.5 support. The pin stays an immutable commit SHA, and the trailing comment names the upstream `release/v1.14` branch that the SHA sits on.\n\nOne behavior change to be aware of: v1.14.0 flipped the action\u0027s `verbose` and `print-hash` inputs to default on, so publish logs will be noisier and will print artifact hashes.\n\nReviewed By: grievejia\n\nDifferential Revision: D117820923\n\nfbshipit-source-id: 345ae56086fdaf87b15ec5763fbc72b4dd7500ae\n"
    },
    {
      "commit": "0c2f22b48ea696a22beab6853595378882d0e423",
      "tree": "4d400d38218b95f8fff32ad8013146512733ae47",
      "parents": [
        "a1ecee47d986665bfa9f707c5d0be766d0b24cc0"
      ],
      "author": {
        "name": "Asuka Minato",
        "email": "i@asukaminato.eu.org",
        "time": "Fri Aug 28 09:23:20 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Fri Aug 28 09:23:20 2026 -0700"
      },
      "message": "fix Semantic auto completion fails on lines preceding comments #4552 (#4554)\n\nSummary:\nFixes https://github.com/facebook/pyrefly/issues/4552\n\nCorrected CRLF-aware comment offsets\n\nPull Request resolved: https://github.com/facebook/pyrefly/pull/4554\n\nTest Plan: add test\n\nReviewed By: stroxler\n\nDifferential Revision: D116160847\n\nfbshipit-source-id: 222f69fd5651b1386979095625b344e13907f4bf\n"
    },
    {
      "commit": "a1ecee47d986665bfa9f707c5d0be766d0b24cc0",
      "tree": "49f94fa23656855a5ae1b6ef1958c4331681cb12",
      "parents": [
        "27e77efc137612b122a2d6992758b8432c9576d0"
      ],
      "author": {
        "name": "Neil Mitchell",
        "email": "ndmitchell@meta.com",
        "time": "Fri Aug 28 04:48:23 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Fri Aug 28 04:48:23 2026 -0700"
      },
      "message": "Bind the decorators of a nameless definition\n\nSummary:\nA decorator with no definition after it crashed the checker:\n\n  $ echo \u0027x:\u003d\u0027 \u003e t.py \u0026\u0026 pyrefly check t.py\n  Internal error: key lacking binding, key\u003dKey::Definition(x ...)\n\nParse-error recovery turns a dangling decorator into a function\ndefinition with an empty name, which `function_def` (and `class_def`)\ndiscarded wholesale. The decorators went with it — but the static\ndefinitions pass had already walked them and declared the names they\ndefine, so a walrus target like the `x` above was left declared with no\nbinding, and looking it up panicked.\n\nA nameless definition really does define nothing, so discarding it is\nright; its decorators are ordinary expressions that happen to precede\nit, so they still need binding. Binding them keeps the two passes\nagreeing about what the statement defines.\n\nAnalyzing those expressions also means names read in them now resolve\nlike any other name, which is why `test_crash_on_decorator_assign`\ngains a `Could not find name` error: `T\u003dTypeVar()` reads an undefined\n`T`, exactly as `T` before a well-formed `def` would.\n\nReviewed By: stroxler\n\nDifferential Revision: D117247062\n\nfbshipit-source-id: 87c7e4f816b5893d409163ec4553740c1eee0af3\n"
    },
    {
      "commit": "27e77efc137612b122a2d6992758b8432c9576d0",
      "tree": "a1ac470b2e1e63939c9f2e07352f117abbb1024e",
      "parents": [
        "dddda2b72e19c5b8b41e7db68e251e35a07dd394"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Fri Aug 28 04:03:27 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Fri Aug 28 04:03:27 2026 -0700"
      },
      "message": "Migrate scalar `movedim` to the V2 DSL\n\nSummary:\nScalar `movedim` and `moveaxis` calls can use the type-level DSL directly, removing their dependence on the V1 transform while preserving precise symbolic shapes and gradual fallback for broad values.\n\nKeep tuple-axis overloads on their existing V1 transform for now. Unbounded tuple `Flag` values lose element precision at the V2 call boundary, so claiming a complete cutover would regress the precise tuple behavior already covered by the stubs. The small `movedim_input_ir` wrapper preserves the public top-level `input` parameter name until the tuple form is migrated.\n\nReviewed By: yangdanny97\n\nDifferential Revision: D113797877\n\nfbshipit-source-id: be63bbb76bd17d4e24a77597ab79ece34af8c1cd\n"
    },
    {
      "commit": "dddda2b72e19c5b8b41e7db68e251e35a07dd394",
      "tree": "ba43711cb77f3e4d95613dc3acffac342df3b060",
      "parents": [
        "4e083d66409c92de16201bf82eba4f48c3976375"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Fri Aug 28 04:03:27 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Fri Aug 28 04:03:27 2026 -0700"
      },
      "message": "Model constructor controls with class `Flag` parameters\n\nSummary:\nSeveral Torch modules still route constructor controls through `uses_shape_dsl` and legacy initialization capture. That keeps shape inference coupled to module-specific state instead of ordinary generic class composition.\n\nParameterize `PixelShuffle`, `GLU`, `Flatten`, `ReflectionPad2d`, and `ReplicationPad2d` with constructor-inferred class `Flag` values, then reference those values directly from generic `forward` annotations. The modules use type-level shape rules, including the shared `flatten_shape` rule introduced by the parent commit, so stored modules and `Sequential` preserve precise controls while dynamic values remain gradual.\n\nReviewed By: avikchaudhuri\n\nDifferential Revision: D113655884\n\nfbshipit-source-id: 3d2bf620e40869be8102f0f238c92434c30c922c\n"
    },
    {
      "commit": "4e083d66409c92de16201bf82eba4f48c3976375",
      "tree": "a658c18bddacbf943cb5bf80f6619137b865f6c2",
      "parents": [
        "2376615ad15b09fcd52e47a83186372b90eb1959"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Fri Aug 28 04:03:27 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Fri Aug 28 04:03:27 2026 -0700"
      },
      "message": "Migrate Tensor and function flatten to the V2 DSL\n\nSummary:\n`Tensor.flatten` and `torch.flatten` still used the legacy shape decorator even though their result depends only on the input shape and dimension arguments.\n\nAdd a shared type-level `flatten_shape` rule and reference it from generic `Flag`-backed signatures. Keep the legacy helper temporarily for `nn.Flatten`; its class-level constructor controls migrate in the following commit. Concrete calls gain scalar and dimension-range validation while gradual inputs remain gradual.\n\nReviewed By: avikchaudhuri\n\nDifferential Revision: D117600820\n\nfbshipit-source-id: 931409e30f6062534a3113b91c2d6418128375a6\n"
    },
    {
      "commit": "2376615ad15b09fcd52e47a83186372b90eb1959",
      "tree": "c2eea6a676e2d784f373671ce6100b7097f8ef63",
      "parents": [
        "220f26105b7f7d2b13caba3c339a8895c1b81f16"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Fri Aug 28 04:03:27 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Fri Aug 28 04:03:27 2026 -0700"
      },
      "message": "Correct the default dimension for `nn.GLU`\n\nSummary:\nPyTorch defaults `nn.GLU` to the last dimension, but the shape stubs modeled its default as dimension 1. This went unnoticed for rank-two inputs, where those dimensions coincide.\n\nUse `-1` consistently in the constructor and legacy shape helper, and cover a rank-three input where the distinction affects the inferred result.\n\nReviewed By: grievejia\n\nDifferential Revision: D117600819\n\nfbshipit-source-id: 63ef027c15e4333f2aad763f02301b15a7d5fc64\n"
    },
    {
      "commit": "220f26105b7f7d2b13caba3c339a8895c1b81f16",
      "tree": "9bd2690e59517738844bd4a1d187471c7bb919a6",
      "parents": [
        "426a3a7cc44710b53e2627d27db15d605a03d393"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Fri Aug 28 04:03:27 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Fri Aug 28 04:03:27 2026 -0700"
      },
      "message": "Preserve `Flag`-bound literals through generic inference\n\nSummary:\n`Flag` values represent runtime values whose literal identity is part of the type. Preserving those values only when a module reached an inferred field was too late: variadic containers such as `Sequential` first capture module types through ordinary generic inference, where nested implicit literals were widened.\n\nWhen a value successfully specializes a `Flag`, recursively mark literals in the accepted type as explicit. This stabilizes nested literals through later TypeVar, TypeVarTuple, field, and proxy-method inference without changing literal widening for values that do not pass through a successful `Flag` specialization. Rejected specializations keep their original recovery type.\n\nReviewed By: avikchaudhuri\n\nDifferential Revision: D113655335\n\nfbshipit-source-id: ca611d5bfececd6e6f2b08c731b4a57711942899\n"
    },
    {
      "commit": "426a3a7cc44710b53e2627d27db15d605a03d393",
      "tree": "15339b412c027e0508f4bb05d57b11180258f7c9",
      "parents": [
        "01e0c7bb4141e2ed33b5ecd257a64dab6e88d6cb"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Fri Aug 28 04:03:27 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Fri Aug 28 04:03:27 2026 -0700"
      },
      "message": "Support literal-preserving `Flag` parameters on classes\n\nSummary:\nConstructor-dependent APIs need class instances to retain literal configuration without side-channel registration. `Flag` parameters previously worked only on functions, so ordinary generic class construction could not model that state.\n\nAllow `Flag` on classes whose effective constructors bind each flag through exactly one direct parameter in every relevant signature. When both `__new__` and `__init__` bind a flag, require the same caller-visible argument and default across phases. Add fresh constructor class arguments to the existing `Flag` call context so literal arguments and runtime defaults are preserved through methods and type-level DSL return annotations, while bare generic annotations remain gradual.\n\nReviewed By: avikchaudhuri\n\nDifferential Revision: D113653144\n\nfbshipit-source-id: 18f4fad87e9bff49123bc4c01977ecb57b2cf688\n"
    },
    {
      "commit": "01e0c7bb4141e2ed33b5ecd257a64dab6e88d6cb",
      "tree": "b5eb1a0442555cacb1cfba83ae7d0c6a8a575bfa",
      "parents": [
        "e7e20736514460574a354e69e9bf0921b21330c7"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Fri Aug 28 04:03:27 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Fri Aug 28 04:03:27 2026 -0700"
      },
      "message": "Preserve class Flag constructor sources\n\nSummary:\nClass `Flag` validation needs to distinguish a constructor parameter directly annotated with the class type parameter from an alias that resolves to the same type. That source distinction is otherwise lost when annotations become callable types.\n\nRecord the sparse parameter indices only for `__init__` and `__new__` annotations that directly name a defining-class `Flag` parameter. Match lowered parameters back to syntax by name so ParamSpec lowering cannot shift the indices. Store the rare metadata behind one pointer and include it in incremental equality.\n\nReviewed By: avikchaudhuri\n\nDifferential Revision: D117600818\n\nfbshipit-source-id: 8d978588910366618d253de44e9a3b285d21c11d\n"
    },
    {
      "commit": "e7e20736514460574a354e69e9bf0921b21330c7",
      "tree": "581865f50d8771b1a734ca9d39c0523ff30e6d8f",
      "parents": [
        "c9c32de54b077de96600c668bf6d9189f7be3865"
      ],
      "author": {
        "name": "Rebecca Chen",
        "email": "rechen@meta.com",
        "time": "Thu Aug 27 22:48:24 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 22:48:24 2026 -0700"
      },
      "message": "Fix scrut tests broken by venv creation warning\n\nSummary: Some of our scrut tests are currently broken because `python3 -m venv` prints some warning about jemalloc. Update the tests to swallow stderr from venv creation unless it fails.\n\nReviewed By: stroxler\n\nDifferential Revision: D117812688\n\nfbshipit-source-id: 47cf157bbd312f619258be7142408321935ddfe0\n"
    },
    {
      "commit": "c9c32de54b077de96600c668bf6d9189f7be3865",
      "tree": "f3da9383516e3143bd2293802b9dd6f4802220f1",
      "parents": [
        "a07f74174cd30ca790bb94d181d85275b45f15dd"
      ],
      "author": {
        "name": "Conner Nilsen",
        "email": "connernilsen@fb.com",
        "time": "Thu Aug 27 21:07:59 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 21:07:59 2026 -0700"
      },
      "message": "Improve LSP path override behavior for windows, homedir paths, and relative paths not starting with `.[.]/` (#4646)\n\nSummary:\nThe previous logic was there just to get things working in the short term. This diff fixes that behavior to work on windows, handle `~`, and handle relative paths that don\u0027t start with a `.`. Simple tests are also added to validate behavior here.\n\nPull Request resolved: https://github.com/facebook/pyrefly/pull/4646\n\nReviewed By: grievejia\n\nDifferential Revision: D117298475\n\nPulled By: connernilsen\n\nfbshipit-source-id: 1ca44a63a05c40a2636fe4bbf79ef29f5a13dad1\n"
    },
    {
      "commit": "a07f74174cd30ca790bb94d181d85275b45f15dd",
      "tree": "74238319c93cbef954a6b2340523524604e6b24d",
      "parents": [
        "22c1525a4eb1943a6ffd18e9b96d506c7f10b814"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Thu Aug 27 17:33:12 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 17:33:12 2026 -0700"
      },
      "message": "cut 1.3.0-dev.3\n\nSummary:\nCut `1.3.0-dev.3`.\n\nThe motivation for cutting now rather than waiting for the usual cadence is the new `pyrefly-numpy-stubs` package earlier in this stack. Publishing is triggered by a change to `version.bzl`, so this bump is what actually uploads the first `pyrefly-numpy-stubs` release and claims the name on PyPI. Until a release goes out, the name is unregistered and anyone could take it.\n\n`Cargo.lock` and the crate manifests are the mechanical `arc autocargo -p pyrefly` regeneration; every hunk is just the version string.\n\nReviewed By: rchen152\n\nDifferential Revision: D117271676\n\nfbshipit-source-id: 23847360bdd91369a14ff7c975d348e3c9e8a5e7\n"
    },
    {
      "commit": "22c1525a4eb1943a6ffd18e9b96d506c7f10b814",
      "tree": "1d15d65a29d7670c133a5a2cf844f2d8681dc5be",
      "parents": [
        "2257162dbbad279bc0e9d4b8731847c1533f1760"
      ],
      "author": {
        "name": "Kyle Into",
        "email": "kylei@meta.com",
        "time": "Thu Aug 27 15:40:16 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 15:40:16 2026 -0700"
      },
      "message": "Back out \"remove me from getting PRs while on PTO\"\n\nSummary:\nOriginal commit changeset: 694c8ce78254\n\nOriginal Phabricator Diff: D115209964\n\nReviewed By: stroxler\n\nDifferential Revision: D117767830\n\nfbshipit-source-id: e25abf392b10f2777e0a1eaad810845c73ff6ea7\n"
    },
    {
      "commit": "2257162dbbad279bc0e9d4b8731847c1533f1760",
      "tree": "7bbcde30ea634c6d8510abfde4888fc60d06219f",
      "parents": [
        "261cf8fad23a32e36eebf004383177ce523bb0f1"
      ],
      "author": {
        "name": "Jia Chen",
        "email": "grievejia@meta.com",
        "time": "Thu Aug 27 15:33:42 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 15:33:42 2026 -0700"
      },
      "message": "Identify customized check arguments\n\nSummary:\nExpose whether a check invocation contains output, behavior, or configuration override options. This lets command integrations reject unsupported argument groups without depending on private field layouts or treating a default-valued argument object as meaningful configuration.\n\nThis functionality will be used in the next diff\n\nReviewed By: stroxler\n\nDifferential Revision: D117454077\n\nfbshipit-source-id: 059a9187d71a8c99936b47b25f5b8384e4638b19\n"
    },
    {
      "commit": "261cf8fad23a32e36eebf004383177ce523bb0f1",
      "tree": "9a9a97af3e1c1f8ecd9572cd0d94e98c1958c0bf",
      "parents": [
        "ddd8605b0b94d47cc89c7aacae35f4d5ff364c92"
      ],
      "author": {
        "name": "Jia Chen",
        "email": "grievejia@meta.com",
        "time": "Thu Aug 27 15:33:42 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 15:33:42 2026 -0700"
      },
      "message": "Run and cache the initial daemon check\n\nSummary:\nInitialize the managed Instagram server lazily on the first check request. The worker loads the canonical Instagram configuration, creates the incremental checker, runs the initial full-project check, and retains both the checker and its result. Later requests reuse that state rather than reinitializing.\n\nConfiguration diagnostics with error severity now make initialization fail and are returned to the client as a terminal `initialization_error`. The loader returns parse diagnostics alongside wheel-selection failures so configuration errors are not silently dropped. Failed initialization leaves the managed server uninitialized, allowing a later request to retry.\n\nThe state-transition test exercises the retry and cache guarantees directly without creating a fake fbsource or testing the full configured Instagram behavior.\n\nReviewed By: stroxler\n\nDifferential Revision: D117135155\n\nfbshipit-source-id: aabbe88679ab8847327b4fe302d4a5b32684de14\n"
    },
    {
      "commit": "ddd8605b0b94d47cc89c7aacae35f4d5ff364c92",
      "tree": "d3019cf2a0546ea86ac2ddef1d65d7452d713990",
      "parents": [
        "59d7d93f45a5894bc7a2ca979c3de9cb7e750e81"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "message": "Infer Torch reshape, view, permute, and repeat_interleave shapes\n\nSummary: These Torch APIs still relied on legacy shape functions, which discarded precise generic shape information in several call forms. Define their results with type-level shape functions. Reshape and view validate element counts, accept zero extents for empty tensors, and fall back safely for list and Sequence arguments. Permute preserves tuple and variadic dimensions while diagnosing invalid permutations. Repeat_interleave computes scalar-repeat extents when no output_size is given, uses a supplied output_size as the runtime-validated result extent, and remains gradual for Tensor-valued repeats when output_size is omitted.\n\nReviewed By: avikchaudhuri\n\nDifferential Revision: D113645206\n\nfbshipit-source-id: e7439f1e807a32b9a461c4acafbd254d9ac325fa\n"
    },
    {
      "commit": "59d7d93f45a5894bc7a2ca979c3de9cb7e750e81",
      "tree": "d0e2882d8bb401a1709c26ef2cd56c61f6283bb3",
      "parents": [
        "59d11026b16598c1c8bd06840ce4dd221b4ddaf6"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "message": "Bind tuple-valued Flags from variadic parameters\n\nSummary: A tuple-valued `Flag` used through an unpacked positional parameter did not identify that parameter as its authoritative inference source. Recognize direct and re-exported `Unpack` annotations from their resolved types, then preserve the binding-source context only while checking those Flag variadics so ordinary TypeVarTuple calls retain their existing call-checking path. Treat an unmatched variadic parameter as an authoritative empty tuple, and reject sources whose inferred tuple is outside the declared Flag domain. This keeps exact literal tuples from `*args` while other occurrences only validate the inferred value.\n\nReviewed By: avikchaudhuri\n\nDifferential Revision: D117557859\n\nfbshipit-source-id: 25c9326cea3d85b41d93be69b6840801506c2d34\n"
    },
    {
      "commit": "59d11026b16598c1c8bd06840ce4dd221b4ddaf6",
      "tree": "2e1d4176935c1fba3673afe88589cd2f9c077d29",
      "parents": [
        "a85847d8a3690d83a7b799aaf06de945134fe6b2"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "message": "Add immutable Flag sequence index lookup\n\nSummary: Type-level shape functions need to find positions in ordered immutable control sequences when implementing APIs such as `permute`. Add `.index(value)` for immutable `Flag` sequences. Concrete lookups return the first matching position, missing values produce a diagnostic, and broad or over-budget inputs remain gradual.\n\nReviewed By: avikchaudhuri\n\nDifferential Revision: D113663947\n\nfbshipit-source-id: 6fb0610ab0658aac8d2b8ea7170b5adba845f5cf\n"
    },
    {
      "commit": "a85847d8a3690d83a7b799aaf06de945134fe6b2",
      "tree": "8a74c5bc50261feefe87d9d9258425222aa1ed51",
      "parents": [
        "dd4c85974f2fd796559457dc083a8183c982367a"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "message": "Preserve fixed shape around gradual dimensions\n\nSummary:\nA fixed `IntTuple` literal or generator can know its rank and most dimensions even when any subset of its elements cannot be computed precisely. Collapsing that result to a wholly gradual shape loses valid sibling information and prevents downstream length and index operations from composing.\n\nRepresent each unknown dimension element as `Int::Int` when tuple cardinality and generator filter membership are known. Unknown generator sources and filters still return a wholly gradual result. Flag sequences also remain wholly gradual because their integer elements have no gradual representation. Invalid expressions continue to propagate.\n\nTreat unrepresentable integer index literals as sign-saturated bounds, matching slice handling, so fixed-rank tuples report them as out of bounds instead of producing a gradual dimension.\n\nReviewed By: avikchaudhuri\n\nDifferential Revision: D113644200\n\nfbshipit-source-id: 5b889297a5f3ad7092d7bc949960816b5f661eca\n"
    },
    {
      "commit": "dd4c85974f2fd796559457dc083a8183c982367a",
      "tree": "5fdb8041336db521a5bffefb5b873533ad867d1b",
      "parents": [
        "6ebabe49b8ce873cc2780272e75432f5e8533bfe"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "message": "Canonicalize bounded computed IntTuple products\n\nSummary:\nV2 `dsl.prod` rejected products containing computed dimensions before canonicalization, blocking precise reshape quotient algebra. Overflow safety already lives in fallible `Int` canonicalization from D113565991, while symbolic literal carriers still need an explicit `i64` representability check.\n\nPreserve the existing zero, identity, and effective-single-factor behavior. For products with multiple effective factors, estimate the number of terms multiplication may expose before canonicalization and keep at most four. The capped, linear-time preflight recursively validates every expression and conservatively carries numerator complexity through division and base complexity through powers, so cancellation and exponent simplification cannot reveal an unbudgeted sum. Definite-one factors are removed before budgeting: symbolic `x ** 0` is recognized directly, while structurally constant-only expressions use the existing checked canonicalizer to recognize results such as `2 - 1`, `1 * 1`, `(-1) ** 2`, and `-3 // -2` without duplicating arithmetic semantics.\n\nReviewed By: avikchaudhuri\n\nDifferential Revision: D113642261\n\nfbshipit-source-id: 77e3b781e29aeef6dc7be15e105558df709ac225\n"
    },
    {
      "commit": "6ebabe49b8ce873cc2780272e75432f5e8533bfe",
      "tree": "cd7e935cdeae10aaf58affef262ac550ca210b9b",
      "parents": [
        "0cfe441cecb839a81f3831f397d0518395255d40"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "message": "Move Torch dim and expand to direct carriers\n\nSummary: Torch rank and expansion APIs still used legacy evaluator hooks even though both operations can be described from their shape carriers. Return rank directly from the `IntTuple` length domain and express expansion through typed target-shape annotations, retaining symbolic and gradual behavior without a second interpreter path.\n\nReviewed By: rchen152\n\nDifferential Revision: D113637505\n\nfbshipit-source-id: a3c4cdd086976df9f7af1231ef644456422a90e2\n"
    },
    {
      "commit": "0cfe441cecb839a81f3831f397d0518395255d40",
      "tree": "125e5347e4a586d00e2b721bf31968c76dcb7daf",
      "parents": [
        "4f3d1b7e1c6486137255d63032eb36f4e407c25b"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "message": "Allow IntTuple lengths to be symbolic\n\nSummary:\n`len(IntTuple)` was evaluated only as a Flag integer, which prevented rank helpers from returning an `Int` dimension when their consumer required one.\n\nRoute IntTuple-backed lengths through the existing deferred-integer validation. The eventual consumer selects the Flag or dimension domain, and retained expression metadata produces the matching value while preserving gradual open-rank behavior and keeping Flag sequences domain-specific.\n\nReviewed By: avikchaudhuri\n\nDifferential Revision: D113637049\n\nfbshipit-source-id: 3a9f36130998690e06d9221297209e2cc3f6f183\n"
    },
    {
      "commit": "4f3d1b7e1c6486137255d63032eb36f4e407c25b",
      "tree": "cb3f8caba7eba76c57ea0211e4176851a6aa6f88",
      "parents": [
        "1c2de0d8759b693e0c921ebb285bfb4555783858"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "message": "Clarify IntTuple-bound argument terminology\n\nSummary: Use direct IntTuple-bound and Elements-argument terminology where the code is describing generic bounds rather than the legacy tuple-backed ShapedArray representation. This keeps the older \"carrier\" term limited to the representation where it has a specific technical meaning. This is part of a general effort to reduce / simplify the jargon involved in the shape types implementation.\n\nReviewed By: avikchaudhuri\n\nDifferential Revision: D117402242\n\nfbshipit-source-id: ea8a4b9ac3e09966115babd79acabfbc43eaff23\n"
    },
    {
      "commit": "1c2de0d8759b693e0c921ebb285bfb4555783858",
      "tree": "3bcd2bb067aa435da1590755b0d111c1794f990e",
      "parents": [
        "386de38df2547ff16495c71d0ce0b34dd3b1fd16"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "message": "Describe the type-level shape DSL migration\n\nSummary: Update contributor guidance to make the type-level DSL the default workflow and clearly identify the remaining decorator-based DSL as legacy migration surface. Record known V1 parity limitations at the affected rules so precision losses remain discoverable after the migration commits land.\n\nReviewed By: avikchaudhuri\n\nDifferential Revision: D117402241\n\nfbshipit-source-id: 2abbb6b5e2b32bc0539cec4a47ec6aa21b6585bc\n"
    },
    {
      "commit": "386de38df2547ff16495c71d0ce0b34dd3b1fd16",
      "tree": "b317f8e1ac17df0db00ffc57e7080865a80666d8",
      "parents": [
        "57b2d786288f52315ef0072a73a222c279e30793"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "message": "Simplify type-level DSL validation metadata\n\nSummary: Clarify the boundary between structural validation and solver-domain validation while reducing duplicate metadata variants. Use one domain-carrying return kind for evaluated expressions, and give the shared comparison operator a domain-neutral name. This makes the retained-AST representation more honest without changing accepted DSL programs.\n\nReviewed By: avikchaudhuri\n\nDifferential Revision: D117402240\n\nfbshipit-source-id: ed9c30255f22ed9bfc1698e986857cc83a882ea5\n"
    },
    {
      "commit": "57b2d786288f52315ef0072a73a222c279e30793",
      "tree": "14c4f316788d603fb25c1e0d69355e5d765cde06",
      "parents": [
        "5c20e57a5dccce075a8ee8f659a228e8e9665659"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "message": "Migrate repeat and tile to the type-level DSL\n\nSummary: Repeat and tile align repetition factors against trailing dimensions and synthesize leading dimensions when needed. Move both APIs to shared type-level tuple arithmetic, covering tuple and variadic calls, symbolic repeats, gradual tuples, and invalid repeat rank.\n\nReviewed By: rchen152\n\nDifferential Revision: D117600817\n\nfbshipit-source-id: f264858cb42472a63358e326dfd1d735857a98e0\n"
    },
    {
      "commit": "5c20e57a5dccce075a8ee8f659a228e8e9665659",
      "tree": "c25f1ab9d5f88b90428af49458bdea9fafc23f72",
      "parents": [
        "bcc864f00f5e98121cc10aa3606e7519122855be"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "message": "Migrate adaptive pooling to the type-level DSL\n\nSummary: Adaptive pooling has fixed supported input ranks and literal scalar or tuple output sizes. Encode each spatial rank directly, preserve gradual results for dynamic and `None`-containing sizes, and model max-pool return-indices overloads.\n\nReviewed By: rchen152\n\nDifferential Revision: D117600815\n\nfbshipit-source-id: e05b904b0466d1eb7599e0cc1d49f1cac49aeb57\n"
    },
    {
      "commit": "bcc864f00f5e98121cc10aa3606e7519122855be",
      "tree": "729b669a1c9e2250dabbb0483f81d652d38e63a0",
      "parents": [
        "bc6cfef39c4cff2cbc8c3abc67e666e945e1d72a"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "message": "Migrate functional padding to the type-level DSL\n\nSummary: Literal padding tuples carry enough information to compute output dimensions and diagnose invalid arity and rank. Use a type-level padding helper for tuples while retaining a gradual list overload for valid dynamic calls.\n\nReviewed By: rchen152\n\nDifferential Revision: D117600814\n\nfbshipit-source-id: 1d2117295b499b7d80428f5ffd545aa45a04d2a9\n"
    },
    {
      "commit": "bc6cfef39c4cff2cbc8c3abc67e666e945e1d72a",
      "tree": "f8502f24789478b54f43028c0474150e2a2be8ce",
      "parents": [
        "6d9c92f1918de92033371e0d991d9a063172e054"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "message": "Migrate functional losses to the type-level DSL\n\nSummary: Functional losses need operation-specific unreduced shapes while sharing the legacy reduction precedence. Model reduction once, derive broadcast, classification, cosine-embedding, and triplet-margin shapes before reduction, and move the functional loss signatures to direct type-level annotations.\n\nReviewed By: avikchaudhuri\n\nDifferential Revision: D113628382\n\nfbshipit-source-id: ddd89f9cb49efd25c63de4dc7ad4ecc85e96ae08\n"
    },
    {
      "commit": "6d9c92f1918de92033371e0d991d9a063172e054",
      "tree": "0940dad21d61d965085ab091b2c9449aef8856bf",
      "parents": [
        "a4a80116380f4d5eab2eb8bcfaf11e6a6ded4808"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 15:03:16 2026 -0700"
      },
      "message": "Evaluate optional boolean and string Flag values\n\nSummary:\nTorch shape helpers need to branch on literal boolean and string options, including optional values whose default is `None`.\n\nExtend type-level DSL validation and evaluation to support boolean truthiness, string equality, and `is None` narrowing for these `Flag` domains. Helper calls distinguish inferred locals, which retain exact declared-domain requirements, from values narrowed by control flow, whose proven domain can flow to a compatible helper parameter. Unsupported parameter types are rejected before evaluation while unknown runtime values continue to produce gradual shapes.\n\nString subclasses use the same shared Flag-domain admission rule in ordinary type-variable solving and DSL-call validation.\n\nReviewed By: avikchaudhuri\n\nDifferential Revision: D113624541\n\nfbshipit-source-id: 253624ee1038804bb4a4efc142a389e288085dd6\n"
    },
    {
      "commit": "a4a80116380f4d5eab2eb8bcfaf11e6a6ded4808",
      "tree": "1a15dbb703da00d48bd183ed55dc07fa91e9d8f5",
      "parents": [
        "dff8740c58cb8d4ea6d50862fa0aaf040a8b1a0d"
      ],
      "author": {
        "name": "Rebecca Chen",
        "email": "rechen@meta.com",
        "time": "Thu Aug 27 14:51:42 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 14:51:42 2026 -0700"
      },
      "message": "Use `Type::transform_toplevel_callable_signatures` more\n\nSummary:\nThe previous diff made the `transform_toplevel_callable_signatures` helper capable of transforming tparams in addition to signatures. This diff uses the helper\u0027s new capabilities to simplify some code that previously had to manually `match` on Type.\n\nMost of these are *not* behavior-preserving: the helper covers more cases than the original code did. This is an improvement and shows why it\u0027s better to use a central helper than to recreate slight variations of the same `match` everywhere.\n\nReviewed By: stroxler\n\nDifferential Revision: D117646811\n\nfbshipit-source-id: 37c4b312e09056d27ec6c940b84d7e4354a0f121\n"
    },
    {
      "commit": "dff8740c58cb8d4ea6d50862fa0aaf040a8b1a0d",
      "tree": "4cbf1a0925ca8f1fdcd1f88ecbc3bc58b6c0d236",
      "parents": [
        "275393d2bbf8438ed8edb2fb5dedffec419f1836"
      ],
      "author": {
        "name": "Rebecca Chen",
        "email": "rechen@meta.com",
        "time": "Thu Aug 27 14:51:42 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 14:51:42 2026 -0700"
      },
      "message": "Improve `Type::transform_toplevel_callable`\n\nSummary:\nMakes `Type::transform_toplevel_callable` capable of transforming both tparams and signatures, which makes it considerably more useful.\n\nI also took the opportunity to add a `_signatures` prefix so the name reflects the fact that it can operate on multiple signatures.\n\nNo functional change - the behavior is exactly the same as before for callers that don\u0027t transform tparams, which no current callers do.\n\nReviewed By: stroxler\n\nDifferential Revision: D117642381\n\nfbshipit-source-id: 59a8110be776d5a1de988114b38ec8e9bf502fbd\n"
    },
    {
      "commit": "275393d2bbf8438ed8edb2fb5dedffec419f1836",
      "tree": "1db97d854d12f5907656ba3341452bc29645dff7",
      "parents": [
        "2730e261067cea4f20c61ef6676c8d645a9d344f"
      ],
      "author": {
        "name": "Rebecca Chen",
        "email": "rechen@meta.com",
        "time": "Thu Aug 27 14:51:42 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 14:51:42 2026 -0700"
      },
      "message": "Get rid of `Type::callable_signatures`\n\nSummary:\nDeletes `Type::callable_signatures` and migrates its callers to `Type::toplevel_callable_signatures`, which returns an iterator instead of a vec and includes tparams.\n\nThis should not cause any behavioral changes. The iterator is probably slightly more performant than a vec, but I haven\u0027t measured anything.\n\nReviewed By: stroxler\n\nDifferential Revision: D117631348\n\nfbshipit-source-id: d955aeb8f84117520d0cc5838e3d364359d2f14f\n"
    },
    {
      "commit": "2730e261067cea4f20c61ef6676c8d645a9d344f",
      "tree": "ecfdd0b07aca7417ae832dc8b81c259e6ded04d5",
      "parents": [
        "b888c14d3d6320891a883a462c3782365fcd3885"
      ],
      "author": {
        "name": "Asuka Minato",
        "email": "i@asukaminato.eu.org",
        "time": "Thu Aug 27 14:32:30 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 14:32:30 2026 -0700"
      },
      "message": "fix False positive for torch.register_* #3988 (#4320)\n\nSummary:\nFixes https://github.com/facebook/pyrefly/issues/3988\n\nRecognizes `self.register_buffer(...)` and `self.register_parameter(...)` in `__init__/__post_init__`, synthesizes correctly typed instance attributes for `torch.nn.Module` subclasses.\n\nPull Request resolved: https://github.com/facebook/pyrefly/pull/4320\n\nTest Plan: add test\n\nReviewed By: stroxler\n\nDifferential Revision: D113871868\n\nfbshipit-source-id: 5821162661e6c9ea7d58227b3512f1074a6ee617\n"
    },
    {
      "commit": "b888c14d3d6320891a883a462c3782365fcd3885",
      "tree": "a21d28ba2a4704d16d3db2a8456ed665deb62667",
      "parents": [
        "2fbc88c88dded402d00cfb606a5f00a92f0a9124"
      ],
      "author": {
        "name": "Asuka Minato",
        "email": "i@asukaminato.eu.org",
        "time": "Thu Aug 27 13:47:09 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 13:47:09 2026 -0700"
      },
      "message": "fix feature request: recognize modules in string #4345 (#4419)\n\nSummary:\nFixes https://github.com/facebook/pyrefly/issues/4345\n\nGo-to-definition now resolves module components inside strings such as \"accounts.urls\".\nClicking accounts opens accounts; clicking urls opens accounts.urls.\nPreserves higher-priority `__all__` symbol navigation.\nOnly activates when the complete string resolves as a module, preventing false positives.\n\nPull Request resolved: https://github.com/facebook/pyrefly/pull/4419\n\nTest Plan: add test\n\nReviewed By: stroxler\n\nDifferential Revision: D114607551\n\nfbshipit-source-id: bfe15e83904786e38141c3a3425203113511e646\n"
    },
    {
      "commit": "2fbc88c88dded402d00cfb606a5f00a92f0a9124",
      "tree": "fa4e0c06f74355830c2546e7c2e997b2b51ecc7c",
      "parents": [
        "bdecc7b87d9ba2b6d5b0669a0cb54c0a96c51c9c"
      ],
      "author": {
        "name": "Aaron Pollack",
        "email": "aaronpollack@meta.com",
        "time": "Thu Aug 27 13:43:59 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 13:43:59 2026 -0700"
      },
      "message": "Keep ASTs a check was asked to retain when reporting CinderX or Pysa\n\nSummary:\nOrdinarily the AST of a module is dropped as soon as its answers are computed,\nbecause nothing reads it after that. The CinderX and Pysa reports do read it,\none step later at `Step::Solutions`, so enabling either of them defers the\neviction to that point.\n\nThat deferred eviction was unconditional, which made it more than a deferral:\nit also dropped ASTs the run had been told to keep. `--report-glean` is exactly\nsuch a caller. It runs the whole check at `Require::Everything` and then reads\neach module\u0027s AST to build its facts, so pairing it with `--report-cinderx`\nleft it with nothing to read and it panicked on the missing AST. Worse than the\ncrash, it happened after CinderX had streamed out its per-module types but\nbefore the project-level `index.json` and `class_metadata.json` were written,\nso the run left behind an output directory that looks complete to anything\nchecking only for `types/`.\n\nGating the deferred eviction on `require.keep_ast()`, the same condition the\n`Step::Answers` site already used, makes it a pure deferral: the reports still\nrelease ASTs as early as they can, and a run that asked to retain them keeps\nthem until it is finished.\n\nNothing covered asking for more than one report in a single run, so this also\nadds an end-to-end test that runs a check with both flags and asserts each\nreport is written in full. Without the fix it reproduces the reported panic\nexactly. The hermetic config recipe the existing incremental-checker tests used\nis now shared, since the new test needs the same thing.\n\nFixes https://github.com/facebook/pyrefly/issues/4683\n\nReviewed By: stroxler\n\nDifferential Revision: D117699183\n\nfbshipit-source-id: 3143a506413321295a47511e969e537f6092279d\n"
    },
    {
      "commit": "bdecc7b87d9ba2b6d5b0669a0cb54c0a96c51c9c",
      "tree": "17f482b589427cafca63eb546456bd5128c50083",
      "parents": [
        "8e496c7dcf5e7f7fa2bd91fbdeef86ec16774e4f"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Thu Aug 27 13:33:18 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 13:33:18 2026 -0700"
      },
      "message": "Avoid invalid assert-not-none code actions\n\nSummary: Limit attribute receiver narrowing actions to missing-attribute diagnostics so an optional attribute value is not mistaken for its owner. Skip actions when the target name is scoped within a lambda or comprehension, where insertion before the enclosing statement is invalid.\n\nReviewed By: rchen152\n\nDifferential Revision: D117709934\n\nfbshipit-source-id: b9e649e3ffb283af45ca5e68bb868b4f9c81cff2\n"
    },
    {
      "commit": "8e496c7dcf5e7f7fa2bd91fbdeef86ec16774e4f",
      "tree": "915cdc26241301a1aba2bb40eee2e8be2d087a15",
      "parents": [
        "1d64c4b605445f43d66162e56592837223b3dabf"
      ],
      "author": {
        "name": "Asuka Minato",
        "email": "i@asukaminato.eu.org",
        "time": "Thu Aug 27 13:33:18 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 13:33:18 2026 -0700"
      },
      "message": "impl code action for narrowing the value with an is not None #4169 (#4244)\n\nSummary:\nFixes https://github.com/facebook/pyrefly/issues/4169\n\nAdds an Add assert x is not None quick fix for optional simple-name values, inserts the assertion with correct indentation before the containing statement.\n\nAvoids unsafe edits for inline statements or complex expressions.\n\nPull Request resolved: https://github.com/facebook/pyrefly/pull/4244\n\nTest Plan: add test\n\nReviewed By: stroxler\n\nDifferential Revision: D113696562\n\nfbshipit-source-id: 644bf0160bdda384b1de530b06973fb8f9abc62d\n"
    },
    {
      "commit": "1d64c4b605445f43d66162e56592837223b3dabf",
      "tree": "f893d0cf628c3a264088739eb8662a52b5f698d0",
      "parents": [
        "6c97ea891490dc6ec2d8cadeee4694c515325e31"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Thu Aug 27 13:19:03 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 13:19:03 2026 -0700"
      },
      "message": "Look for one canonical interpreter path in a virtual environment\n\nSummary:\nVirtual environment discovery probes a list of possible interpreter paths:\n`bin/python3`, `bin/python`, `python3`, and `python` on macOS and Linux, and\n`Scripts\\python.exe` and `python.exe` on Windows. Only the first entry of each\nplatform\u0027s list can ever match a virtual environment. Every builder, including\n`venv`, `virtualenv`, and `uv`, writes `bin/python` or `Scripts\\python.exe`,\nand writes version-suffixed names such as `python3` and `python3.12` only as\nadditional names for that same interpreter. The remaining entries describe\nenvironments that cannot exist, and one of them is not even a virtual\nenvironment layout: an interpreter directly beside `pyvenv.cfg` is how Conda\nlays out an environment prefix, which `conda.rs` already handles.\n\nThe list is an artifact of the walker this code replaced, which searched a\nproject tree to a fixed depth and so reached those paths incidentally. Turning\nthat reach into an explicit list promoted it to a specification.\n\nProbe the single canonical path instead, so the code no longer implies that\nenvironments it cannot encounter are reachable. An environment lacking that\npath was modified after creation and needs an explicitly configured\ninterpreter, which is what the documentation already tells users to do.\n\nReviewed By: connernilsen\n\nDifferential Revision: D116510541\n\nfbshipit-source-id: 799f75df3ab8723799368a6b2c396f088c5fd863\n"
    },
    {
      "commit": "6c97ea891490dc6ec2d8cadeee4694c515325e31",
      "tree": "f1ea59e94df79ddaf8fa042990c7959693881954",
      "parents": [
        "9284873bd1b1ca1de4a18371bef5426e1dfc749d"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Thu Aug 27 13:19:03 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 13:19:03 2026 -0700"
      },
      "message": "Fix venv test fixture that broke Windows CI (#4582)\n\nSummary:\nPull Request resolved: https://github.com/facebook/pyrefly/pull/4582\n\n`test_find_interpreter_precedence_venv` fails on Windows. The fixture builds\nits virtual environment out of a `python3.exe` sitting directly in the\nenvironment root, but no virtual environment on Windows looks like that: the\ninterpreter is always `Scripts\\python.exe`. Venv discovery therefore found\nnothing and fell through to the interpreter on `$PATH`, which is what the\nassertion reported.\n\nBuild the fixture the way the platform actually lays out a virtual\nenvironment, so the test exercises a shape that discovery is meant to find.\nJoining each path component separately also keeps the directory separator\nnative, instead of embedding a `/` inside a single component and reporting\n`...\\venv/python3.exe` on failure.\n\nReviewed By: connernilsen\n\nDifferential Revision: D116509185\n\nfbshipit-source-id: 3b9a6c5393c0fdb85b5c26478c406a6b40964667\n"
    },
    {
      "commit": "9284873bd1b1ca1de4a18371bef5426e1dfc749d",
      "tree": "a5026036290e28b01ffa3d904bf96ecf965e4819",
      "parents": [
        "8520f0a61f0c333a0ea61425760f8f0d90185b2e"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Thu Aug 27 11:09:32 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 11:09:32 2026 -0700"
      },
      "message": "Store calculation results in tagged box pointers\n\nSummary:\nThe broader goal of this stack is to eliminate the `Arc` stored for every calculation result, reducing allocation, atomic refcount, and memory overhead. Earlier diffs made published and provisional answers borrowable and removed downstream dependencies on Arc ownership.\n\nThis diff replaces permanent per-answer `Arc` storage with `Box` allocations. Each result slot is a single atomic pointer whose low bits independently record whether publication is pending and whether the pointer is a non-owning alias. Untagged pointers own their allocation, while alias slots point at an owning slot in the same result table. Because the table retains and drops all of its slots together, aliases can share an answer without refcount operations or double-freeing the allocation. An aligned wrapper guarantees the two tag bits for every answer type.\n\nThe pointer directly addresses the answer, avoiding the arena lookup and metadata required by compact integer slots. SCC generations already own boxed answers, so final publication transfers those boxes into their result slots without copying the answer.\n\nReviewed By: grievejia\n\nDifferential Revision: D117087366\n\nfbshipit-source-id: f857a696951a296cfd1ccd7bf8d202f991611399\n"
    },
    {
      "commit": "8520f0a61f0c333a0ea61425760f8f0d90185b2e",
      "tree": "bb4893b6b232d02e4fdbc6f1741765255f7f9a8c",
      "parents": [
        "8d00e30264b40d39368a2590bef3c5b6fd476026"
      ],
      "author": {
        "name": "Rebecca Chen",
        "email": "rechen@meta.com",
        "time": "Thu Aug 27 11:08:19 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 11:08:19 2026 -0700"
      },
      "message": "Recognize bound method tparams in overload checks\n\nSummary:\nUses `Type::toplevel_callable_signatures` in `check_signature_consistency` to get a callable\u0027s tparams and signature together, rather than needing to look them up separately.\n\nThis is a minor behavioral change. We previously ignored BoundMethod tparams, which I\u0027m pretty sure was not intentional.\n\nReviewed By: stroxler\n\nDifferential Revision: D117632070\n\nfbshipit-source-id: f8db133fd9fb0a3f1c268bb7d4fa8f5cbedc9283\n"
    },
    {
      "commit": "8d00e30264b40d39368a2590bef3c5b6fd476026",
      "tree": "3d7d28da123adf0edd15a1b841a57ca4077a21a7",
      "parents": [
        "00fc9d0f16ff51138bb6476724f117674d631e88"
      ],
      "author": {
        "name": "Rebecca Chen",
        "email": "rechen@meta.com",
        "time": "Thu Aug 27 11:08:19 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 11:08:19 2026 -0700"
      },
      "message": "Simplify functools code using `Type::visit_toplevel_callable`\n\nSummary: Rewrites a manual `match` to use `visit_toplevel_callable`. I split this out of the previous diff because it\u0027s technically a behavior change: if an overloaded function has only one signature (which is an error anyway), we no longer give up and use the fallback.\n\nReviewed By: stroxler\n\nDifferential Revision: D117644706\n\nfbshipit-source-id: cb593229ccdc665870f33686ca33fc142548acf4\n"
    },
    {
      "commit": "00fc9d0f16ff51138bb6476724f117674d631e88",
      "tree": "6d80f292a961779c512d785624599351a51062b5",
      "parents": [
        "ded66250b164781cb151e4a99b2a42da19b2a9d2"
      ],
      "author": {
        "name": "Rebecca Chen",
        "email": "rechen@meta.com",
        "time": "Thu Aug 27 11:08:19 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 11:08:19 2026 -0700"
      },
      "message": "Improve `Type::visit_toplevel_callable`\n\nSummary:\nReplaces a visitor over a callable type\u0027s signatures with a getter that returns an iterator over the signatures. This is much more ergonomic to use.\n\nAlso includes the callable\u0027s tparams in the signature. This will let us clean up some code that had to manually `match` on callable types just to get the tparams (see next two diffs).\n\nThis should not cause any behavioral changes. It may make us a bit faster because the iterator is not always fully consumed, but I haven\u0027t timed anything.\n\nReviewed By: stroxler\n\nDifferential Revision: D117627691\n\nfbshipit-source-id: 1efe6a7fea4f39cf4aff5cc679f8a2ecf6e78d0c\n"
    },
    {
      "commit": "ded66250b164781cb151e4a99b2a42da19b2a9d2",
      "tree": "6a33f7877f83bc330bd8a645a85e7a0b0971e0f5",
      "parents": [
        "337821c8cd9be3cd1f5b14cce7d2258b8c2bf2b9"
      ],
      "author": {
        "name": "Rebecca Chen",
        "email": "rechen@meta.com",
        "time": "Thu Aug 27 11:08:19 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 11:08:19 2026 -0700"
      },
      "message": "Simplify `Type::transform_toplevel_func_metadata`\n\nSummary: No functional change. The previous diff replaced `visit_toplevel_func_metadata` with a simpler `toplevel_func_metadata` getter. This diff replaces the parallel `transform_toplevel_func_metadata` with `toplevel_func_metadata_mut`.\n\nReviewed By: stroxler\n\nDifferential Revision: D117622059\n\nfbshipit-source-id: 38a62015a133da224b26139311078226b54322ab\n"
    },
    {
      "commit": "337821c8cd9be3cd1f5b14cce7d2258b8c2bf2b9",
      "tree": "05fe495be76adf897c69debb3cc0519670afdc06",
      "parents": [
        "5ec3aec52806c6856595c62a24205135ea8fd4ef"
      ],
      "author": {
        "name": "Rebecca Chen",
        "email": "rechen@meta.com",
        "time": "Thu Aug 27 11:08:19 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 11:08:19 2026 -0700"
      },
      "message": "Simplify `Type::visit_toplevel_func_metadata`\n\nSummary:\nNo functional change.\n\nReplaces an unnecessary \"visit\" function over a type\u0027s function metadata with a function that just returns the metadata.\n\nWe had quite a few one-line helpers that wrapped the visit function; I deleted some unused ones and in-lined ones that had only one call site.\n\nReviewed By: stroxler\n\nDifferential Revision: D117614925\n\nfbshipit-source-id: d3cdf16ac7368e9481d85190346eb294d79947d1\n"
    },
    {
      "commit": "5ec3aec52806c6856595c62a24205135ea8fd4ef",
      "tree": "96ccd2574fd212f28a5da51a123922292ccb56a6",
      "parents": [
        "f6b5338ff435eb16744015a705036162b906ebbd"
      ],
      "author": {
        "name": "Rebecca Chen",
        "email": "rechen@meta.com",
        "time": "Thu Aug 27 11:08:19 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 11:08:19 2026 -0700"
      },
      "message": "Merge `SyntheticSelf` and `SyntheticCallableResidual` quantified origins\n\nSummary:\nNo functional change.\n\n`SyntheticCallableResidual` was used whenever we created a quantified out of thin air, and most of the usages have nothing to do with callable residuals. `Synthetic` is a more accurate name.\n\nOnce we have a general `Synthetic` variant, `SyntheticSelf` being separate reads a little weirdly, so let\u0027s turn it into an `is_self` flag on `Synthetic`.\n\nReviewed By: stroxler\n\nDifferential Revision: D117447742\n\nfbshipit-source-id: 75b43da6254dca345b88bef788c59168e94e56fe\n"
    },
    {
      "commit": "f6b5338ff435eb16744015a705036162b906ebbd",
      "tree": "baa63c94f2b7eb18bf8c52ae6a3239bb3e2097fe",
      "parents": [
        "6ab2adf6964500d9aee48cc40861eea07bdf7c46"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Thu Aug 27 08:45:04 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 08:45:04 2026 -0700"
      },
      "message": "Optimize `safe_delete_file_code_action`\n\nSummary:\nBefore this diff, deciding whether a file is safe to delete performed unnecessary work:\n\n1. It queried the *transitive* rdep closure when only immediate rdeps are needed\n2. It parsed the AST for each module from (1) to try to scan for imports naming the target\n\nInstead, it\u0027s enough to simply look at the direct rdeps for the module, which are already recorded. An rdeps existence is enough to determine that the module is needed. We don\u0027t need to look at the AST.\n\nReading the edge is also more correct. The AST scan missed a genuine case where a rdep is found, but rdeps are recorded automatically as part of Pyrefly\u0027s incremental logic, so an rdep entry is exactly what we want.\n\nBoth before and after this diff, the notion of \"safe\" is partial. The check assumes that Pyrefly has seen all possible downstream users of a file, but that is not always true. We might not see consumers outside of a library, for example. Pyrefly is also lazy by design, where it might not have even seen all the files in your project. (For example, if indexing is turned off.) This behavior is unchanged.\n\nReviewed By: stroxler\n\nDifferential Revision: D117632598\n\nfbshipit-source-id: d1db6d4e3945d97996cff82f6160ca91faad62dd\n"
    },
    {
      "commit": "6ab2adf6964500d9aee48cc40861eea07bdf7c46",
      "tree": "575c6cccf7c500001084fad84db063d046d93ed0",
      "parents": [
        "b0c2a79fd54da22b218fbbcd5928d9250f0a243a"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Thu Aug 27 08:45:04 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 08:45:04 2026 -0700"
      },
      "message": "Only run `safe_delete_file_code_action` when `allow_refactor` is set\n\nSummary:\n`safe_delete_file_code_action` produces a `refactor.delete` action, but it was\ncalled after the `if allow_refactor` block rather than inside it, so unlike the\nother nineteen refactors it ran whatever the client asked for. Almost all\n`textDocument/codeAction` traffic is `only: [\"quickfix\"]`, which means the\naction was both computed and returned for requests that had said they did not\nwant it.\n\nFurthermore, the code action implementation is quite expensive (and unnecessarily so, see the next commit). Internal telemetry shows that this is ~20% of all time spent handling `codeAction` requests and 2.5% of all time spent in the LSP queue.\n\nReviewed By: stroxler\n\nDifferential Revision: D117632597\n\nfbshipit-source-id: 82ca2188513fe2136b3a613ddbdae47d87b97bf9\n"
    },
    {
      "commit": "b0c2a79fd54da22b218fbbcd5928d9250f0a243a",
      "tree": "482dc38a65a0a69b0aed9a676aceb42184faa166",
      "parents": [
        "a8ca33ab4784275620b6721e587512f5a82219b6"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Thu Aug 27 08:08:36 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 08:08:36 2026 -0700"
      },
      "message": "Separate building a non-convergence error from emitting it\n\nSummary:\n`check_and_report_non_convergent_member` read an SCC member\u0027s answers, decided whether the member had actually failed to converge, rendered the message, and emitted it, all while holding the answers. Its caller could only run it after `commit_final_answers`, because whether to report at all depends on the commit succeeding, so the caller first copied every candidate answer out of the SCC to keep them alive across that call.\n\nSplit the deciding and rendering half from the emitting half. `make_non_convergent_diagnostic` reads the answers and returns `Option\u003cNonConvergentDiagnostic\u003e`, an owned value holding the range, message, and optional details. `emit_non_convergent_diagnostic` takes that value and an `ErrorCollector`. The caller renders diagnostics while the SCC is still intact and emits them after committing, so the answers no longer need to outlive the commit.\n\nRendering up front also lets the convergence check fall out through `filter_map` instead of an early return during reporting, and leaves emission free of the answer\u0027s key type, so the same-module and cross-module branches no longer each need their own `dispatch_anyidx!`.\n\nNo behavior change: the same members produce the same errors in the same collectors.\n\nReviewed By: rchen152\n\nDifferential Revision: D117565823\n\nfbshipit-source-id: d682819605d93896ccac05155d78b8b983c73ef4\n"
    },
    {
      "commit": "a8ca33ab4784275620b6721e587512f5a82219b6",
      "tree": "e3f6b3e51d711e387c996064b8579a59177dd2cf",
      "parents": [
        "0bee259c2e9587c3c183cd15f59468b2bcbea762"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Thu Aug 27 08:08:36 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 08:08:36 2026 -0700"
      },
      "message": "Stop prescribing inlining for the result slot helpers\n\nSummary:\nThe result slot carries eleven inlining directives: `#[inline]` on the tag helpers and on the lookups that read them, and `#[inline(never)]` layered on top of `#[cold]` for the two waiting paths. None of them changes what the compiler does. The helpers and lookups are private and small enough to inline on their own, and `#[cold]` already applies the inliner\u0027s cold-callsite threshold, which is what keeps the waiting path out of the lookup.\n\nSaying it anyway is worse than saying nothing, because a directive reads as a decision someone made for a reason, and the next reader has to work out whether that reason still holds. The `#[cold]` markers stay: they carry information the compiler cannot derive, namely that these paths are unlikely and belong away from the lookup. `handle_failed_cas` already used `#[cold]` alone, so the three cold paths are now consistent.\n\nReviewed By: rchen152\n\nDifferential Revision: D117262632\n\nfbshipit-source-id: 1b4c016a82e9a801896de6faa90cdb510f897675\n"
    },
    {
      "commit": "0bee259c2e9587c3c183cd15f59468b2bcbea762",
      "tree": "a4e6eae5e1df996fab8d600476c6f8f94eca04f0",
      "parents": [
        "d1bce59fdc86f3c9b1ac687e3a73d2766d474035"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Thu Aug 27 08:08:36 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 08:08:36 2026 -0700"
      },
      "message": "Name the type-erased answer\n\nSummary:\nSCC iteration state and the answer scope store answers with their key type erased, spelled `Arc\u003cdyn Any + Send + Sync\u003e` at roughly forty sites. Callers recovered the answer by naming its storage rather than its key, so every change to how answers are allocated has to be applied at each downcast.\n\n`AnyAnswer` gives the erased answer a name, mirroring `Any`. Callers now name the key that produced the answer -- `downcast_ref::\u003cK\u003e()` -- and the representation stays private to `answers.rs`.\n\nThe outer `Arc` in that encoding is also unnecessary, and this diff drops it while it is already rewriting every one of these call sites. A borrowed erased answer once had to yield an owned `Arc\u003cK::Answer\u003e`, which is why an already-shared answer was wrapped in a second `Arc`. Removing owned calculation result reads retired that requirement, so nothing has needed the outer `Arc` since. `AnyAnswer` erases the answer\u0027s own `Arc` and recovers ownership through `Arc::downcast`, saving an allocation and an indirection per erased answer.\n\nReviewed By: grievejia\n\nDifferential Revision: D117262630\n\nfbshipit-source-id: 1c84cc59872979886c5beef827c58877035f20b2\n"
    },
    {
      "commit": "d1bce59fdc86f3c9b1ac687e3a73d2766d474035",
      "tree": "61619a10c08558c6862d06403c336c37ad0a448a",
      "parents": [
        "c2e38547533e438f14f2ce8a4c586a1cfffd7518"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Thu Aug 27 08:08:36 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 08:08:36 2026 -0700"
      },
      "message": "Return calculated answers by value\n\nSummary:\nThis stack eliminates per-answer `Arc` storage to reduce allocation and atomic refcount overhead and improve memory use. Once consumers borrow calculated results, producer helpers should also stop encoding the temporary Arc-backed storage policy in their return types.\n\nThis diff makes calculation helpers return plain values and leaves the result-storage boundary responsible for wrapping them in the current Arc owner. Behavior and storage remain unchanged, but calculation code is now independent of the wrapper that the final conversion will replace with `Box`.\n\nReviewed By: grievejia\n\nDifferential Revision: D117087365\n\nfbshipit-source-id: 75ede7dc612f9fbff0bfbb522c8b2278f17a2c13\n"
    },
    {
      "commit": "c2e38547533e438f14f2ce8a4c586a1cfffd7518",
      "tree": "551277fa5ab7489e446be79606e1216c8c401489",
      "parents": [
        "f81ff125758344205e123face570ec72d25a97a8"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Thu Aug 27 08:08:36 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 08:08:36 2026 -0700"
      },
      "message": "Make calculation aliases explicit during solving\n\nSummary:\nThe broader goal of this stack is to eliminate the `Arc` stored for every\ncalculation result. Several bindings produce exactly the result of another\ncalculation, so preserving that relationship avoids copying or separately\nowning an equivalent answer.\n\nAfter calculation consumers move to borrowed results, `get_idx_arc` remains\nonly to preserve sharing for `Forward`, `PatternCapture`, and\n`ForwardToFirstUse`. This diff makes those aliases explicit in `SolveResult`\nand teaches ordinary result publication to store another strong reference to\nthe target slot\u0027s allocation. This preserves the existing shared-`Arc`\nbehavior while removing the final owned result-read API.\n\nSCC iterations continue to materialize independent answers. Preserving an\nalias there would require identifying the fully forced target in the final\ngeneration and retaining that allocation, while the existing implementation\nalready loses sharing during SCC iteration.\n\nMaking aliases explicit in storage prepares a later diff to replace the\nper-answer `Arc` with owned boxes and non-owning alias pointers.\n\nReviewed By: grievejia\n\nDifferential Revision: D117087364\n\nfbshipit-source-id: 73718c8eb9b2658ef6abeba5fa3062245ba5addc\n"
    },
    {
      "commit": "f81ff125758344205e123face570ec72d25a97a8",
      "tree": "c1a10db3ac54cdd641ec91146a130023d1f9fc00",
      "parents": [
        "15252d1dac1fc5007cc6876cb8158f42505ee6f7"
      ],
      "author": {
        "name": "David Tolnay",
        "email": "dtolnay@meta.com",
        "time": "Thu Aug 27 07:46:57 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 07:46:57 2026 -0700"
      },
      "message": "Update lsp-server from 0.9.0 to 0.10.0\n\nReviewed By: ndmitchell\n\nDifferential Revision: D117648886\n\nfbshipit-source-id: 170abec64cd68ba787a5f8621f8f9fb66e367fe2\n"
    },
    {
      "commit": "15252d1dac1fc5007cc6876cb8158f42505ee6f7",
      "tree": "9bb70c5b43cb9a1b923bccfe16f26e827396ce4f",
      "parents": [
        "6f60f7d8c980fbacc510ccdb8d888a22f577e06d"
      ],
      "author": {
        "name": "David Tolnay",
        "email": "dtolnay@meta.com",
        "time": "Thu Aug 27 07:44:21 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 07:44:21 2026 -0700"
      },
      "message": "Update lsp-server from 0.8.0 to 0.9.0\n\nReviewed By: ndmitchell\n\nDifferential Revision: D117647324\n\nfbshipit-source-id: 54eacc6d2e81ef99961af9491b86637f5e38aafe\n"
    },
    {
      "commit": "6f60f7d8c980fbacc510ccdb8d888a22f577e06d",
      "tree": "92028ce6cde43e0854974a28898c5c515858c1ab",
      "parents": [
        "b2851b717cfc42092fff151889e9118182cf728c"
      ],
      "author": {
        "name": "David Tolnay",
        "email": "dtolnay@meta.com",
        "time": "Thu Aug 27 00:03:43 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 00:03:43 2026 -0700"
      },
      "message": "Update ruff crates from 0.0.9 to 0.0.10\n\nReviewed By: diliop, samwgoldman\n\nDifferential Revision: D117541792\n\nfbshipit-source-id: 0db289737b516b2b395b4aa7cf8efa3883a2219a\n"
    },
    {
      "commit": "b2851b717cfc42092fff151889e9118182cf728c",
      "tree": "7cddb3fbf798060797b39c22e9719fd7a09f2c6a",
      "parents": [
        "8dc67c5a0ebca091a35fb7256073438433768e70"
      ],
      "author": {
        "name": "David Tolnay",
        "email": "dtolnay@meta.com",
        "time": "Thu Aug 27 00:01:51 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 00:01:51 2026 -0700"
      },
      "message": "Update ruff crates from 0.0.8 to 0.0.9\n\nReviewed By: samwgoldman, diliop\n\nDifferential Revision: D117541790\n\nfbshipit-source-id: 6b98fe90b1092530fc83f7e5c22ff373f253c60e\n"
    },
    {
      "commit": "8dc67c5a0ebca091a35fb7256073438433768e70",
      "tree": "2020b88960b74b3c838ec32636e11b3b101c4b7d",
      "parents": [
        "278beb7ea2f32d4e8bd5408bc4c57aa548172218"
      ],
      "author": {
        "name": "David Tolnay",
        "email": "dtolnay@meta.com",
        "time": "Thu Aug 27 00:01:08 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 00:01:08 2026 -0700"
      },
      "message": "Update ruff crates from 0.0.7 to 0.0.8\n\nReviewed By: samwgoldman, diliop\n\nDifferential Revision: D117541789\n\nfbshipit-source-id: c65eb5c9de629af11343c24ddee5b9131e2c8196\n"
    },
    {
      "commit": "278beb7ea2f32d4e8bd5408bc4c57aa548172218",
      "tree": "6cc82a6a1c5852b3152bc2b3ceb3834cf68c0dbf",
      "parents": [
        "9b8603351df6352abaa71a303b47d3a38c6784e0"
      ],
      "author": {
        "name": "David Tolnay",
        "email": "dtolnay@meta.com",
        "time": "Thu Aug 27 00:00:24 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Thu Aug 27 00:00:24 2026 -0700"
      },
      "message": "Update ruff crates from 0.0.6 to 0.0.7\n\nReviewed By: diliop, samwgoldman\n\nDifferential Revision: D117541787\n\nfbshipit-source-id: fe9044d93cc95eef276f00397f98118c60b6f674\n"
    },
    {
      "commit": "9b8603351df6352abaa71a303b47d3a38c6784e0",
      "tree": "700c96adccee7e82aa71eff3cc383aae443b60bc",
      "parents": [
        "4e52467b81b4749f62d56d14aaf5d8186496ff1c"
      ],
      "author": {
        "name": "David Tolnay",
        "email": "dtolnay@meta.com",
        "time": "Wed Aug 26 22:55:57 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 22:55:57 2026 -0700"
      },
      "message": "Update lsp-server from 0.7.9 to 0.8.0\n\nReviewed By: diliop\n\nDifferential Revision: D117546230\n\nfbshipit-source-id: a7d5847c884ab44e0f2ed659a7260f0a35e6ad94\n"
    },
    {
      "commit": "4e52467b81b4749f62d56d14aaf5d8186496ff1c",
      "tree": "c1ea1d73b2209a0ff15b1606a2a1d6c233db21d9",
      "parents": [
        "269d5a71ad3dfe7d0a4734fb839c4fc40036a899"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Wed Aug 26 18:23:18 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 18:23:18 2026 -0700"
      },
      "message": "Declare some more torch APIs the stubs were hiding\n\nSummary:\nThese stubs are a partial package: `py.typed` contains `partial`, so a submodule they do not ship falls back to the real torch stubs. That fallback is per-module, not per-name. `torch/__init__.pyi` is shipped, so it shadows torch\u0027s own outright, and every name it omits stops existing on `torch` for any target that depends on these stubs — including code with no interest in shapes.\n\nThe stub was complete enough for the models annotated so far, but not for their reverse dependencies. Adding the stub dep to one model target made `torch.manual_seed`, `torch.save` and `torch.load` disappear from unrelated targets in `hammer/v3/models/udd_fm_v3` that merely share a dependency edge, which is how this surfaced.\n\nDeclare the missing names rather than suppressing the errors they cause. They are gaps, not a case of the stubs being more precise than torch: nothing about `torch.save` is shape-dependent, and code calling it is not wrong. Signatures follow torch\u0027s own. `manual_seed` returns `torch._C.Generator`, which resolves through the same partial-package fallback described above; the import carries a comment explaining that, since it is not obvious that a name defined nowhere in the package resolves at all.\n\n`Tensor.clamp_min` and `device.type` came from the same sweep. Their siblings `clamp_max` and `device.index` are added alongside them, being the same gap.\n\nApplied to both the trunk stub and the pinned copy in `python/tensor-shapes/v0`, for the reasons given earlier in this stack: the pinned copy is what callers build against now, and the trunk copy is what the next release mirrors forward.\n\nReviewed By: coursekevin\n\nDifferential Revision: D116956303\n\nfbshipit-source-id: fdabe438a5102781a68b143fb33ca42f4af948fb\n"
    },
    {
      "commit": "269d5a71ad3dfe7d0a4734fb839c4fc40036a899",
      "tree": "2da46afc60d3335ea348ce59b0f2878c606b7708",
      "parents": [
        "b408bc1fdc914cb7cabce58b620117ac6b0442de"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Wed Aug 26 18:23:18 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 18:23:18 2026 -0700"
      },
      "message": "Add bitwise operators to the Tensor stub\n\nSummary:\nThe torch stub declares no bitwise operators, so combining two boolean masks does not type check:\n\n    non_empty_sid_mask \u003d non_empty_sid_mask \u0026 (sid_value !\u003d 0)\n    # `\u0026` is not supported between `Tensor[...]` and `Tensor[...]`\n\nThat is a gap rather than a deliberate restriction. Masks are produced by the comparison operators, which the stub does declare, so the natural next step of combining them fails. Any model adopting shape types hits this, and the only recourse today is a suppression at each site.\n\nAdd `__and__`, `__or__`, `__xor__` and their reflected forms, plus `__invert__`. These are elementwise on integer and boolean tensors and broadcast exactly as the comparison operators do, so they reuse the same overload shape: a tensor operand broadcasts, a scalar operand preserves `Self`.\n\nOne case does not work, and it is a checker bug rather than a stub gap: `x | y` between two tensors resolves to a union type instead of dispatching to `__or__`. `x.__or__(y)` and `x | True` both give the right answer, and `\u0026` and `^` are unaffected, so the PEP 604 union reading only wins when both operands are tensors. `test_or_between_two_tensors_is_read_as_a_union` records the current behavior so the suite stays green and a future fix is visible. Worth fixing separately in the checker; `\u0026` is the common case for mask combination and it works.\n\nReviewed By: avikchaudhuri\n\nDifferential Revision: D116644514\n\nfbshipit-source-id: 60f40dabe7c64a62592dcc943d26f147d6c4fa65\n"
    },
    {
      "commit": "b408bc1fdc914cb7cabce58b620117ac6b0442de",
      "tree": "240d8b2eca7af79f6c5d26008185fd0aaadc2bc1",
      "parents": [
        "887ecefcc02a279085aa2df30af4ee71d02ce73f"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Wed Aug 26 18:23:18 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 18:23:18 2026 -0700"
      },
      "message": "Add TorchScript shape annotation stripper\n\nSummary:\nSome Meta production paths still compile PyTorch models through TorchScript, which parses source annotations and also consults class `__annotations__`. Add a Meta-specific helper package under `facebook/torch-stubs` that erases Pyrefly shape-only annotations for those legacy TorchScript paths without making source rewriting part of the core `shape_extensions` API.\n\nNOTE: We probably should open-source this eventually because torchscript is used some in the industry at large. But it\u0027s a non-maintained framework (superseded by `torch.compile` years ago), which means it\u0027s only used in very brownfield codebases, and I don\u0027t expect any external early adopters to have that flavor. So I prefer to keep it internal for now, and only open-source when we\u0027ve seen it work in production and have some confidence. We need it internally because lots of core ads and recommender systems models depend on it.\n\nReviewed By: coursekevin\n\nDifferential Revision: D110196475\n\nfbshipit-source-id: b4f5f9e8aad25d09582d9dc5a08254130ef85d39\n"
    },
    {
      "commit": "887ecefcc02a279085aa2df30af4ee71d02ce73f",
      "tree": "1ca0470f8e5e25e362d0aaeec783699e48a71c25",
      "parents": [
        "647610b5df6c94739c2eeeb77e93fe33c26a38c0"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Wed Aug 26 18:23:18 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 18:23:18 2026 -0700"
      },
      "message": "Enable TorchScript runtime compatibility on import\n\nSummary:\nTorchScript reads class attribute annotations back out of `__annotations__`, which are evaluated when the class body runs. `enable_torchscript_runtime_compat()` therefore had a latent ordering hazard: calling it from `main()`, or from anywhere after the annotated model class was imported, was silently too late and left `Int[...]` un-erased on exactly the annotations TorchScript was about to read.\n\nReplace the function with a `shape_extensions.torchscript` module that re-exports the whole `shape_extensions` surface and enables compatibility mode as an import side effect. Callers import that module instead of `shape_extensions`, so the ordering is guaranteed by the import system rather than by convention. Compatibility mode remains process-global and one-way, which the module docstring now states explicitly: `Int` is the same class object either way, so the patch is visible to code that imports `shape_extensions` directly.\n\nRe-exporting requires `shape_extensions` to declare `__all__`, which it now does.\n\nReviewed By: coursekevin\n\nDifferential Revision: D116500372\n\nfbshipit-source-id: 70ac4866653acbf6bf162ddb0a9d1bf89fa5cad1\n"
    },
    {
      "commit": "647610b5df6c94739c2eeeb77e93fe33c26a38c0",
      "tree": "7488a4f7733d0b034a4fe150a4fd6d1713d8a85e",
      "parents": [
        "50e3701fbf30417a95b13bc59c9f0483503dc9c5"
      ],
      "author": {
        "name": "Jia Chen",
        "email": "grievejia@meta.com",
        "time": "Wed Aug 26 18:09:07 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 18:09:07 2026 -0700"
      },
      "message": "Guard against recursive protocol member checking in __getattr__ self validation\n\nSummary:\nFixes https://github.com/facebook/pyrefly/issues/4632\n\n### Why\nAttribute fallback can start a new subset query while Pyrefly checks whether a receiver satisfies the protocol in an explicit `self` annotation. The new query does not share the local `Subset` cycle detector. Repeated protocol member lookup can therefore recurse until the process exhausts its stack.\n\nA coinductive result from this cross-query guard must also stay out of the persistent protocol and TypedDict caches. Such a result depends on an active recursive assumption and can be incorrect when Pyrefly repeats the comparison independently.\n\n### What\n- Add a thread-state guard for active `(got_type, protocol_class_type, member_name)` checks.\n- Apply the guard only when a protocol member is provided by `__getattr__` or `__getattribute__` fallback.\n- Record when the guard uses a coinductive assumption.\n- Propagate that state through protocol and TypedDict comparisons so Pyrefly does not cache assumption-dependent results.\n- Add tests for the original recursion, specialization-sensitive guard keys, and persistent protocol-cache safety through runtime protocol overlap.\n\n### Why it works\nThe guard tracks active member checks across nested subset queries. An exact repeated check succeeds coinductively instead of starting another recursive fallback call. Concrete protocol specializations remain distinct because the key contains `ClassType`. Cacheable comparisons record whether they used this assumption and skip persistent cache writes when they did.\n\nReviewed By: stroxler\n\nDifferential Revision: D117112934\n\nfbshipit-source-id: 22f8bff21d3e6c999224fb985f7a29ff59c62dff\n"
    },
    {
      "commit": "50e3701fbf30417a95b13bc59c9f0483503dc9c5",
      "tree": "8450cc4424f3de1388c2a56af9e2ce6f90e87575",
      "parents": [
        "41544de7322d689c2b5832a72f28ceef19401aff"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Wed Aug 26 16:10:42 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 16:10:42 2026 -0700"
      },
      "message": "Remove owned calculation result reads\n\nSummary:\nThis stack eliminates per-answer `Arc` storage to reduce allocation and atomic refcount overhead and improve memory use. After stable published, provisional, and committed-state views are available, remaining result consumers no longer need ownership of the storage wrapper.\n\nThis diff converts stored-result APIs from Arc handles to references bounded by `Answers`, `Solutions`, or a solver view. Reporting structures that genuinely outlive their source clone the underlying values directly. A narrow `get_idx_arc` path remains temporarily for forward-like calculation producers so they can preserve the existing shared result without copying `TypeInfo`; the following diff replaces that final use with explicit alias storage.\n\nReviewed By: rchen152\n\nDifferential Revision: D117087363\n\nfbshipit-source-id: 33096b4f20b01e4887c531673eebdf58f97b7c00\n"
    },
    {
      "commit": "41544de7322d689c2b5832a72f28ceef19401aff",
      "tree": "e3bc6bcbb2a04fbbdaedbb6b5773c4a79a3b036f",
      "parents": [
        "7493ed4c549f72150e650fa35043367e0cb16cac"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Wed Aug 26 16:10:42 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 16:10:42 2026 -0700"
      },
      "message": "Add a stable committed-state reader\n\nSummary:\nThis stack eliminates per-answer `Arc` storage to reduce allocation and atomic refcount overhead and improve memory use. Removing Arc-returning APIs requires every borrower, including tests and committed-state queries, to hold an owner for the full lifetime of the returned reference.\n\nThis diff introduces `StateReader`, which owns the state read lock and exposes completed solutions for the lifetime of that stable view. It lets committed-state callers borrow calculation results instead of requesting Arc handles, preparing those remaining consumers for the storage conversion.\n\nReviewed By: rchen152\n\nDifferential Revision: D117087362\n\nfbshipit-source-id: 1a3cde87f7df407a91255bd0ab1c3d412320d432\n"
    },
    {
      "commit": "7493ed4c549f72150e650fa35043367e0cb16cac",
      "tree": "ff2db92b4b102b2b4547a3acf269ef5235002cd8",
      "parents": [
        "803bdee7d66906f7564ba835bc259fdc40b51594"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Wed Aug 26 16:10:42 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 16:10:42 2026 -0700"
      },
      "message": "Borrow unchanged class fields\n\nSummary:\nThis stack eliminates per-answer `Arc` storage to reduce allocation and atomic refcount overhead and improve memory use. Once solver lookups can borrow stored answers, APIs that sometimes synthesize values should borrow the common case and own only the exceptional result.\n\nThis diff changes class-member lookup to return `Cow\u003cClassField\u003e`. Ordinary stored fields remain borrowed, while synthesized `Any` members and fields instantiated through class type arguments use the owned variant. This removes another downstream dependency on Arc-backed results without changing lookup behavior.\n\nReviewed By: rchen152\n\nDifferential Revision: D117087361\n\nfbshipit-source-id: ec7968a984df2c60d269b940ad5ebfdae2ae6eea\n"
    },
    {
      "commit": "803bdee7d66906f7564ba835bc259fdc40b51594",
      "tree": "77e4b0049f88465ec00503f68b743375940905f9",
      "parents": [
        "1e656e20a4e219be954c033280e6135914cfd024"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Wed Aug 26 16:10:42 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 16:10:42 2026 -0700"
      },
      "message": "Borrow unchanged type aliases\n\nSummary:\nThis stack eliminates per-answer `Arc` storage to reduce allocation and atomic refcount overhead and improve memory use. Once solver lookups can borrow stored answers, APIs that sometimes synthesize values should borrow the common case and own only the exceptional result.\n\nThis diff changes type-alias resolution to return `Cow\u003cTypeAlias\u003e`. Direct values and unchanged references borrow stable solver storage, while missing aliases and references requiring substitution return owned values. This removes another downstream dependency on Arc-backed results without forcing unnecessary clones.\n\nReviewed By: rchen152\n\nDifferential Revision: D117087360\n\nfbshipit-source-id: e2e98ee34cba1a77d3b95d1c2f17f714b68d3e73\n"
    },
    {
      "commit": "1e656e20a4e219be954c033280e6135914cfd024",
      "tree": "7beefdcaa00065faf52e5a835c7ef11b84d32766",
      "parents": [
        "941f0762d9ab85909c05add4b1f56114afc466b9"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Wed Aug 26 16:10:42 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 16:10:42 2026 -0700"
      },
      "message": "Borrow calculated answers through solver scopes\n\nSummary:\nThis stack eliminates per-answer `Arc` storage to reduce allocation and atomic refcount overhead and improve memory use. After giving provisional SCC answers stable storage, retaining cross-module answer providers, and preserving intentional `TParams` sharing, downstream solver APIs can borrow calculated results directly.\n\nThis diff changes `AnswersSolver`, `LookupAnswer`, and exported-key solving to return references for completed and provisional calculations. Published results borrow from `Answers` or `Solutions`; provisional SCC results borrow from their retained generation. Truly synthesized shortcut and depth-limit answers are retained by `AnswerScope` so they can use the same scope lifetime.\n\nSolver consumers now accept the borrowed values directly. `TParams` consumers can clone the semantic `Arc\u003cTParams\u003e` when constructing shared `TArgs` without copying the underlying parameters. Forward-like producers temporarily use a narrow `get_idx_arc` compatibility API, preserving their existing cheap `Arc` clone without copying `TypeInfo`. A later diff makes these aliases explicit and removes that final owned-result API.\n\nReviewed By: rchen152\n\nDifferential Revision: D117087359\n\nfbshipit-source-id: c70410b108d41418a5389a8021ac0fea8e6c9089\n"
    },
    {
      "commit": "941f0762d9ab85909c05add4b1f56114afc466b9",
      "tree": "b7d308539fe32f1290344e631704f2bb802d4c41",
      "parents": [
        "d200ce1482882ef4f4090934c5271cf7213be7fc"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Wed Aug 26 16:10:42 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 16:10:42 2026 -0700"
      },
      "message": "Return the placeholder answer the SCC decided to keep\n\nSummary:\n`on_placeholder_recorded` decides whether a cycle-breaking node keeps the placeholder it was handed. It declines when the node has already advanced to `HasPlaceholder` or `Done`, so that placeholder recording cannot regress a completed node. It returned nothing, so `attempt_to_unwind_cycle_from_here` held its own copy of the placeholder and returned that regardless of the decision. When the decision went the other way the caller handed out an answer, carrying a `Var` of its own, that the SCC had never recorded.\n\nHave the deciding function report what it decided: `on_placeholder_recorded` returns the answer the node ends up with, `set_iteration_placeholder` passes it along, and the caller returns that instead of its own. Which answer a node keeps is unchanged, including the defense-in-depth check.\n\nReviewed By: stroxler\n\nDifferential Revision: D117303005\n\nfbshipit-source-id: 85cef02bd5738c2f312b58ff5fd9e5d629742b7c\n"
    },
    {
      "commit": "d200ce1482882ef4f4090934c5271cf7213be7fc",
      "tree": "24f2f7bbf7fab4ea5bb0f630093d5371fa1a8f1d",
      "parents": [
        "1ef4af9296895f1d77c7704ae21fa61a7fe298bc"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Wed Aug 26 16:10:42 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 16:10:42 2026 -0700"
      },
      "message": "Share type parameter answers explicitly\n\nSummary:\nThis stack eliminates per-answer `Arc` storage to reduce allocation and atomic refcount overhead and improve memory use. Most calculated results can eventually be stored in `Box` and borrowed directly, but `TParams` are intrinsically shared because they are copied into `TArgs`.\n\nThis diff makes `KeyTParams::Answer` an `Arc\u003cTParams\u003e`. Existing owned-result APIs continue to return the same semantic `Arc\u003cTParams\u003e` to callers, while a following diff can return `\u0026Arc\u003cTParams\u003e` and clone the shared value without copying the underlying type parameters. The later general storage conversion can then remove the calculation-owned `Arc` while preserving the sharing required by `TArgs`.\n\nReviewed By: grievejia\n\nDifferential Revision: D117087358\n\nfbshipit-source-id: 851545ddb70abcb21f640bd4fd3db219aa0973f3\n"
    },
    {
      "commit": "1ef4af9296895f1d77c7704ae21fa61a7fe298bc",
      "tree": "45111105d032d71feabc6fb6ca95ff71c8527041",
      "parents": [
        "c99366ef424cf5c6191da31d1e62b9428fd6444f"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Wed Aug 26 16:10:42 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 16:10:42 2026 -0700"
      },
      "message": "Look up answer slots infallibly\n\nSummary:\n`Answers::new` gives every binding a result slot, so looking one up by `Idx` can only fail when the index came from different `Bindings` than the answers being indexed -- a mistake no caller can sensibly recover from. Returning `Option` invited callers to handle it anyway, and several did so silently: `reserve_preliminary` reported a missing slot as \"did not reserve\", and the two `publish_reserved`/`rollback_reserved` paths reported it as \"nothing was pending\".\n\nThe slot lookups now panic instead of returning `Option`, so the invariant is stated once, where it is established, rather than being rediscovered by each caller. `AnswersSolver::get_answer_slot` no longer needs its own unwrap.\n\nReviewed By: ndmitchell, grievejia\n\nDifferential Revision: D117262724\n\nfbshipit-source-id: 7556f2c7fda8e16c9b484f6e6438111ac3a1a9a6\n"
    },
    {
      "commit": "c99366ef424cf5c6191da31d1e62b9428fd6444f",
      "tree": "0487e33fd0c4b3e45a5ac50b6cb023710ae33ff5",
      "parents": [
        "103ea5da8ffb387303c31f0b37a0fb71c8a5f1d1"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Wed Aug 26 16:10:42 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 16:10:42 2026 -0700"
      },
      "message": "Cache cross-module answer providers\n\nSummary:\nThis stack eliminates per-answer `Arc` storage to reduce allocation and atomic refcount overhead and improve memory use. Borrowing cross-module results requires their owning `Answers` or `Solutions` data to remain alive for the full solver scope.\n\nThis diff adds an append-only provider cache to `AnswerScope`, keyed by the target module allocation. The transaction retains module allocations, so the pointer-based key remains unique for the cache lifetime. Each entry owns either `(Bindings, Answers)` or `Solutions`, allowing repeated cross-module lookups to reuse one stable provider without repeatedly loading `ArcSwap` state.\n\n`lookup_answer` now uses the cached provider but continues returning owned `Arc` results through the existing APIs. A following diff can therefore introduce borrowed-result APIs and migrate their consumers independently.\n\nReviewed By: stroxler\n\nDifferential Revision: D116650392\n\nfbshipit-source-id: 67d0301a714aeaa98fb889f2be2adbff7c50e580\n"
    },
    {
      "commit": "103ea5da8ffb387303c31f0b37a0fb71c8a5f1d1",
      "tree": "78b8a7ebfd56c5812d3cdeafe14ec59ac527e19c",
      "parents": [
        "5e1672f85c179c53c8bb8e78de171b131a8ef497"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Wed Aug 26 16:10:42 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 16:10:42 2026 -0700"
      },
      "message": "Separate solver context and answer lifetimes\n\nSummary:\nThis stack eliminates per-answer `Arc` storage. Borrowing calculation results requires the owner of an answer to outlive the returned reference, but a cross-module solver may use helper inputs that exist only for the duration of that lookup.\n\nGive `AnswersSolver` separate `ctx` and `scope` lifetimes. The context lifetime covers short-lived inputs used while solving, while the scope lifetime covers bindings, calculation state, and answer storage that may back returned references. This is behavior preserving and prepares the next diff to return references without tying them to temporary cross-module solver values.\n\nReviewed By: stroxler\n\nDifferential Revision: D115792158\n\nfbshipit-source-id: ea4302ec5f61ae1dd1992dd321e18f71a6c791ee\n"
    },
    {
      "commit": "5e1672f85c179c53c8bb8e78de171b131a8ef497",
      "tree": "0a2a1c22053938b43aa024993c93ae55ec780cb9",
      "parents": [
        "00e8ee1405ccbec9a2ac0c70796ceb376571113e"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Wed Aug 26 16:10:42 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 16:10:42 2026 -0700"
      },
      "message": "Retain provisional answer generations in solver scopes\n\nSummary:\nThis stack eliminates per-answer `Arc` storage to reduce allocation and atomic refcount overhead. SCC provisional answers are one remaining source of per-answer ownership: borrowing them requires their generation storage to remain stable even when SCC stack mutations release the original owner.\n\nThis diff introduces `AnswerScope`, an append-only owner that retains each borrowed generation at most once. Each top-level binding and SCC iteration gets a scope, and temporary cross-module solver views share it. Provisional answer references are tied to the scope lifetime, so they remain valid independently of SCC stack mutations without unsafe code or calculation-wide answer retention. The values remain `Arc`-backed for now; this establishes the ownership boundary needed to replace them with boxes later.\n\nReviewed By: stroxler\n\nDifferential Revision: D115789811\n\nfbshipit-source-id: b15e1263cc1dfc5fa0fb397ba0743431821b3a58\n"
    },
    {
      "commit": "00e8ee1405ccbec9a2ac0c70796ceb376571113e",
      "tree": "8ced40eee8a71f3dc0f7c84dcfaf88f4c28e824c",
      "parents": [
        "71ae1346d08cd5aa77736f867dd921bc3f994717"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Wed Aug 26 14:34:13 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 14:34:13 2026 -0700"
      },
      "message": "Reject a candidate on the characters it contains\n\nSummary:\nFiltering on length dismisses almost every candidate on the workloads that hurt\nmost, but it is blind to the one it cannot help with: a scope whose names are all\nabout as long as the name being looked up. There the filter admits everything and\nthe distance computation runs once per candidate.\n\nLength is not the only cheap lower bound available. Folding each name\u0027s characters\ninto a 32-bit mask gives another: an edit changes at most two buckets, since a\nsubstitution can clear the bucket of the character it removes and set the one it\nadds, while an insertion or deletion touches only one. So two names within\ndistance `d` differ in at most `2 * d` buckets, and a wider difference rules a\ncandidate out before any table is built.\n\nThe mask is recorded next to the length, in the same pass over the name, and costs\nnothing to store: `StaticInfo` had 40 bytes of content in a 48-byte slot, so both\nvalues fit in padding it already had and the map entry stays at exactly one cache\nline.\n\n`Candidate` has no such slack and rounds to 32 bytes. An earlier version narrowed\nthe length and the priority to `u32` to hold it at 24, which was worth 20% back\nwhen every candidate was built into a chained iterator. That no longer\nreproduces: `offer_if` builds each candidate where it is tested and nothing\noutlives the comparison, so the struct never has to reach memory. Narrowing again\nnow measures a wash -- 3.11 ms against 3.14 ms on `unresolved_same_length`, and\n5% worse on `real_unknown` -- so both fields keep the width the rest of the\nsearch uses.\n\nBoth sides of the mask must be built by the same function over the same units. A\nfirst attempt folded bytes, which is not a bound on distance in characters -- one\ncharacter substitution can change two bytes and flip four buckets -- and it\ndropped a legitimate suggestion for a non-ASCII name.\n\n| benchmark | current | previous | baseline |\n|---|---:|---:|---:|\n| `real_long_typo` | 121 us | 114 us (0.94x) | 168.01 ms (1390.5x) |\n| `unresolved_long` (whole file) | 5.41 ms | 5.74 ms (1.06x) | 139.07 ms (25.7x) |\n| `discarded_errors` (whole file) | 4.97 ms | 5.04 ms (1.02x) | 136.57 ms (27.5x) |\n| `unresolved_spread` (whole file) | 3.25 ms | 4.89 ms (1.51x) | 101.97 ms (31.4x) |\n| `suggestion_typo_100k` | 3.65 ms | 4.83 ms (1.32x) | 82.53 ms (22.6x) |\n| `unresolved_same_length` (whole file) | 3.17 ms | 14.62 ms (4.62x) | 47.49 ms (15.0x) |\n| `real_unknown` | 421 us | 2.99 ms (7.09x) | 31.77 ms (75.4x) |\n| `real_typo` | 318 us | 1.92 ms (6.04x) | 24.29 ms (76.3x) |\n| `nested_scopes_16_deep` (whole file) | 2.14 ms | 2.26 ms (1.06x) | 4.69 ms (2.19x) |\n| `suggestion_small_scope` | 3 us | 18 us (5.63x) | 146 us (45.2x) |\n\n`same_length` is the case this is aimed at and gains most, which is the whole\nargument for it: the length filter could do nothing there.\n\n`same_length` is the case this is aimed at and gains most, which is the whole\nargument for it: the length filter could do nothing there.\n\nReviewed By: rchen152\n\nDifferential Revision: D117083066\n\nfbshipit-source-id: 129653be75276f9117ae5eccbab8c40d1f4d7186\n"
    },
    {
      "commit": "71ae1346d08cd5aa77736f867dd921bc3f994717",
      "tree": "4baa41f76c10f4612c704a35254720bc24541087",
      "parents": [
        "ed3587c18ff50c2dedecdba10cd334db95921ad6"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Wed Aug 26 14:34:13 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 14:34:13 2026 -0700"
      },
      "message": "Take each candidate\u0027s length from the caller\n\nSummary:\nThe search\u0027s first act on every candidate was to count its characters, to decide\nwhether the lengths were close enough for the name to be worth reading at all. On\na large generated scope that is billions of counts. Profiling the parent puts 18%\nof `real_unknown` in `Candidate::measured`, which is that count and nothing else,\nagainst 59% in the distance computation the count exists to avoid.\n\nCounting is the wrong operation to make faster, because it is the same count every\ntime: the candidates do not change between lookups. `Candidate` now carries the\nlength, `StaticInfo` records it when the static scope is built, and callers with\nonly a handful of names use `Candidate::measured` instead.\n\nOne thing about the shape of this is load-bearing and invisible in the source.\nThe length rejection stays inline and everything it guards does not: left in one\npiece, the body is too large for the compiler to fold into the caller, so it\ncosts a call for every candidate, almost all of which are about to be discarded.\n`Search::rejects` is `#[inline]` and `Search::consider` is `#[inline(never)]`,\nwhich is what recovers the rest.\n\n| benchmark | current | previous | baseline |\n|---|---:|---:|---:|\n| `real_long_typo` | 114 us | 1.91 ms (16.7x) | 168.01 ms (1473.1x) |\n| `unresolved_long` (whole file) | 5.74 ms | 6.03 ms (1.05x) | 139.07 ms (24.2x) |\n| `discarded_errors` (whole file) | 5.04 ms | 4.92 ms (0.98x) | 136.57 ms (27.1x) |\n| `unresolved_spread` (whole file) | 4.89 ms | 5.35 ms (1.09x) | 101.97 ms (20.9x) |\n| `suggestion_typo_100k` | 4.83 ms | 5.95 ms (1.23x) | 82.53 ms (17.1x) |\n| `unresolved_same_length` (whole file) | 14.62 ms | 16.03 ms (1.10x) | 47.49 ms (3.25x) |\n| `real_unknown` | 2.99 ms | 4.72 ms (1.58x) | 31.77 ms (10.6x) |\n| `real_typo` | 1.92 ms | 3.64 ms (1.89x) | 24.29 ms (12.6x) |\n| `nested_scopes_16_deep` (whole file) | 2.26 ms | 2.23 ms (0.98x) | 4.69 ms (2.08x) |\n| `suggestion_small_scope` | 18 us | 20 us (1.11x) | 146 us (8.04x) |\n\n`same_length` is unchanged in both sets, as it should be. Nothing there can be\nrejected on length, so every candidate reaches the distance computation\nregardless and the count was never the cost. That case is what the next commit\nis for.\n\n`same_length` is unchanged, as it should be: nothing there can be rejected on\nlength, so every candidate reaches the distance computation regardless and the\ncount was never the cost.\n\nReviewed By: rchen152\n\nDifferential Revision: D117083067\n\nfbshipit-source-id: 77f501f5c42ed2fb6788d01bb9c4ec9a429f97d0\n"
    },
    {
      "commit": "ed3587c18ff50c2dedecdba10cd334db95921ad6",
      "tree": "04043b16957cb7eb925bb54560eef75c01f63cdc",
      "parents": [
        "75181f64857cf468e3cc677fb29939ee1f658012"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Wed Aug 26 14:34:13 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 14:34:13 2026 -0700"
      },
      "message": "Give the distance computation an upper bound\n\nSummary:\nThe search asked for an exact edit distance to every name in scope and then threw\naway all but the closest. Computing an exact distance for a name that is nowhere\nnear is the bulk of the work, and none of it is needed: the caller only ever asks\nwhether a candidate is *close*.\n\n`distance_at_most` saturates instead. Three bounds fall out of that. Two names\nwhose lengths differ by more than the bound cannot be within it, since every edit\nchanges the length by at most one. A path costing at most `bound` cannot stray\nmore than `bound` cells from the diagonal, so only that band has to be filled,\nwhich makes the computation linear in the name length rather than quadratic. And\nonce every cell in a row exceeds the bound, no continuation can come back under\nit, so the rest of the table is abandoned.\n\nThe caller supplies `min(max_distance, best distance so far)`, so each match found\nnarrows the search for everything after it.\n\nLengths are counted in characters rather than bytes so that non-ASCII identifiers\nstay correct, though the common all-ASCII case compares bytes directly and skips\ndecoding. `strsim` moves to `test_deps`, since the only remaining use is the\nreference implementation the differential test checks against.\n\n| benchmark | current | previous | baseline |\n|---|---:|---:|---:|\n| `real_long_typo` | 1.91 ms | 167.64 ms (87.9x) | 168.01 ms (88.1x) |\n| `unresolved_long` (whole file) | 6.03 ms | 81.24 ms (13.5x) | 139.07 ms (23.0x) |\n| `discarded_errors` (whole file) | 4.92 ms | 4.96 ms (1.01x) | 136.57 ms (27.8x) |\n| `unresolved_spread` (whole file) | 5.35 ms | 54.51 ms (10.2x) | 101.97 ms (19.1x) |\n| `suggestion_typo_100k` | 5.95 ms | 82.51 ms (13.9x) | 82.53 ms (13.9x) |\n| `unresolved_same_length` (whole file) | 16.03 ms | 28.32 ms (1.77x) | 47.49 ms (2.96x) |\n| `real_unknown` | 4.72 ms | 32.02 ms (6.78x) | 31.77 ms (6.73x) |\n| `real_typo` | 3.64 ms | 24.66 ms (6.78x) | 24.29 ms (6.68x) |\n| `nested_scopes_16_deep` (whole file) | 2.23 ms | 4.36 ms (1.96x) | 4.69 ms (2.11x) |\n| `suggestion_small_scope` | 20 us | 144 us (7.11x) | 146 us (7.22x) |\n\n`same_length` gains least by a wide margin, and that is the shape of the\nresult: where no candidate can be dismissed on length, all that is left is the\nband and the row abandonment.\n\n`same_length` gains least by a wide margin, and that is the shape of the result:\nwhere no candidate can be dismissed on length, all that is left is the band and\nthe row abandonment.\n\nReviewed By: rchen152\n\nDifferential Revision: D117083069\n\nfbshipit-source-id: 250c444a6e7cbbc5e83c2d9d60e816d2617f7e46\n"
    },
    {
      "commit": "75181f64857cf468e3cc677fb29939ee1f658012",
      "tree": "d6d25296fb6a2b90f42ebc35a87b546fcf45b8d8",
      "parents": [
        "e5fd1372e27b110dd7250cbf845f655d8133d7d6"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Wed Aug 26 14:34:13 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 14:34:13 2026 -0700"
      },
      "message": "Search the scopes and the builtins in one pass\n\nSummary:\nSuggesting a name ran three searches. One over the enclosing scopes, one over the\nbuiltin wildcards, and then a third over the two winners to pick between them.\nThe third had to invent priorities to do it, passing 0 and 1 and so discarding the\nlookup depth the first search had just used.\n\nThe builtins are simply the outermost scope, so there is one search here, over one\niterator: the names in scope innermost first, then the builtins at a priority no\nreal scope can reach. That is what the three-way version computed, by a longer\nroute.\n\nThis also moves the last of the decision-making out of the binding code. `Scopes`\nnow offers the candidates and nothing else -- which names are visible, in what\norder, at what depth -- while every judgement about which one to suggest belongs\nto `best_suggestion`. It is also what lets the search be benchmarked directly,\nsince one call now stands for the whole thing.\n\nSharing a pass has a side benefit: the bound is the best distance found so far, so\na close builtin narrows the search for the scope names after it, and the other way\nround.\n\n| benchmark | current | previous | baseline |\n|---|---:|---:|---:|\n| `real_long_typo` | 167.64 ms | 167.87 ms (1.00x) | 168.01 ms (1.00x) |\n| `unresolved_long` (whole file) | 81.24 ms | 78.19 ms (0.96x) | 139.07 ms (1.71x) |\n| `discarded_errors` (whole file) | 4.96 ms | 4.95 ms (1.00x) | 136.57 ms (27.5x) |\n| `unresolved_spread` (whole file) | 54.51 ms | 54.00 ms (0.99x) | 101.97 ms (1.87x) |\n| `suggestion_typo_100k` | 82.51 ms | 81.55 ms (0.99x) | 82.53 ms (1.00x) |\n| `unresolved_same_length` (whole file) | 28.32 ms | 27.12 ms (0.96x) | 47.49 ms (1.68x) |\n| `real_unknown` | 32.02 ms | 32.69 ms (1.02x) | 31.77 ms (0.99x) |\n| `real_typo` | 24.66 ms | 24.14 ms (0.98x) | 24.29 ms (0.99x) |\n| `nested_scopes_16_deep` (whole file) | 4.36 ms | 4.36 ms (1.00x) | 4.69 ms (1.08x) |\n| `suggestion_small_scope` | 144 us | 141 us (0.98x) | 146 us (1.02x) |\n\nNot flat: the whole-file cases run about 4% slower, and fusing the pass is what\ncosts it. Before, one loop filled a `Vec` while a second computed distances over\nthat slice, so each had a branch pattern of its own. Now a `flat_map` over the\nscopes, a `filter_map` for the flow probe and a `chain` for the builtins all run\nbetween one distance computation and the next, and that history displaces what\nthe predictor had learned about the inner loop of `levenshtein`. `perf` puts the\ncost exactly there: 4% longer for 3.6% fewer instructions, IPC down from 5.71 to\n5.53, and branch misses up 40% -- from 17M to 80M inside `levenshtein` alone,\na function this diff does not touch. Collecting the fused iterator into a `Vec`\nrecovers all of it, which is what identifies the laziness rather than the\nmerging as the cost. That collect is the allocation the next diff removes, and\ntwo diffs later these same benchmarks run in a fraction of this.\n\nReviewed By: rchen152\n\nDifferential Revision: D117083068\n\nfbshipit-source-id: 781496c49be236a70b354562ef65363c4804ed9b\n"
    },
    {
      "commit": "e5fd1372e27b110dd7250cbf845f655d8133d7d6",
      "tree": "ba0cb8f1c0b5500c544725f414c7a7e6454f69ee",
      "parents": [
        "d9c19fcc7c739a3424aefa3a142ceefa5e8db5f3"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Wed Aug 26 14:34:13 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 14:34:13 2026 -0700"
      },
      "message": "Collect suggestion candidates in one flow-aware pass\n\nSummary:\nThe candidate search walked two maps per scope: the flow, holding names bound on\nthe path to this point, and the static map, holding every name bound anywhere in\nthe scope. Each flow name then cost a lookup back into the static map to recover\nits declaration, and both arms were filtered by comparing a declaration\u0027s\nposition against the reference\u0027s.\n\nPosition is the wrong question. What decides whether a name is worth offering is\nwhether it would have resolved, which is what `look_up_name_for_read` already\nworks out -- per scope, from the flow and the static map together. Asking it once\nper candidate would be far too slow, so this reproduces its rule in bulk: take\nthe names a scope declares, and where the flow is still being walked, keep only\nthe ones it has bound. Across a function boundary the order of execution is\nunknowable, so everything the scope declares counts and the flow is not consulted\nat all.\n\nThree things the positional filter got wrong come right as a result. A name the\nstatement being written assigns is no longer offered to a reference inside it,\nbecause the flow has bound nothing of that statement yet -- `aby \u003d ab + 42` stops\nsuggesting `aby`. A walrus is offered, because it binds partway through and the\nrest of the statement really can see it. And a helper defined further down the\nfile is offered from inside a function, which the positional filter refused\nthough the name resolves there perfectly well.\n\nClass bodies stop needing a rule of their own. They took the flow path\nexclusively, which only made sense while the two maps were searched separately.\n\nA candidate whose length differs from the missing name by more than\n`MAX_DISTANCE` cannot match whatever tier it falls in, so it is dismissed before\nthe flow is asked. In a large scope that is nearly all of them, which is what\nkeeps a probe per candidate off the hot path.\n\n| benchmark | current | previous | baseline |\n|---|---:|---:|---:|\n| `real_long_typo` | 167.87 ms | 167.11 ms (1.00x) | 168.01 ms (1.00x) |\n| `unresolved_long` (whole file) | 78.19 ms | 136.22 ms (1.74x) | 139.07 ms (1.78x) |\n| `discarded_errors` (whole file) | 4.95 ms | 4.87 ms (0.98x) | 136.57 ms (27.6x) |\n| `unresolved_spread` (whole file) | 54.00 ms | 100.34 ms (1.86x) | 101.97 ms (1.89x) |\n| `suggestion_typo_100k` | 81.55 ms | 79.96 ms (0.98x) | 82.53 ms (1.01x) |\n| `unresolved_same_length` (whole file) | 27.12 ms | 48.10 ms (1.77x) | 47.49 ms (1.75x) |\n| `real_unknown` | 32.69 ms | 32.59 ms (1.00x) | 31.77 ms (0.97x) |\n| `real_typo` | 24.14 ms | 24.69 ms (1.02x) | 24.29 ms (1.01x) |\n| `nested_scopes_16_deep` (whole file) | 4.36 ms | 4.58 ms (1.05x) | 4.69 ms (1.08x) |\n| `suggestion_small_scope` | 141 us | 139 us (0.99x) | 146 us (1.03x) |\n\nThe three whole-file cases where a scope is walked run in a little over half the\ntime. The rest are direct searches that never touch a scope, so they do not\nmove, which is the shape the change predicts.\n\nReviewed By: rchen152\n\nDifferential Revision: D117083074\n\nfbshipit-source-id: df806aaa0039b455bf65561e67ef85d171674027\n"
    },
    {
      "commit": "d9c19fcc7c739a3424aefa3a142ceefa5e8db5f3",
      "tree": "112bbde4daa1563db77475c229350bd18950b313",
      "parents": [
        "0fd32921747715f8e8094544385510c0a643afc6"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Wed Aug 26 14:34:13 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 14:34:13 2026 -0700"
      },
      "message": "Only work out a suggestion for an error that will be shown\n\nSummary:\nAn unresolved name searched the whole enclosing scope for something to suggest\nbefore anything had decided the error was going to be reported. Modules pulled in\nbelow `Require::Errors` collect with `ErrorStyle::Never` and discard everything\nthey are given, so for those the search was pure waste -- and it is not a cheap\nsearch.\n\n`with_detail_from` takes a closure and runs it only when the collector is live.\nThe unresolved-name path passes one, so the scope walk happens when the message\nwill be read and not otherwise.\n\nWhere the call sat matters as much as when it runs. It was ahead of the\n`is_special_name` branch, so a name that was never going to produce this error\npaid for a suggestion anyway. That branch now computes nothing. The class body\nbranch stays eager, because it needs the name for the binding it creates rather\nthan for the message.\n\n| benchmark | current | previous | baseline |\n|---|---:|---:|---:|\n| `real_long_typo` | 167.11 ms | 167.71 ms (1.00x) | 168.01 ms (1.01x) |\n| `unresolved_long` (whole file) | 136.22 ms | 137.37 ms (1.01x) | 139.07 ms (1.02x) |\n| `discarded_errors` (whole file) | 4.87 ms | 138.22 ms (28.4x) | 136.57 ms (28.1x) |\n| `unresolved_spread` (whole file) | 100.34 ms | 101.54 ms (1.01x) | 101.97 ms (1.02x) |\n| `suggestion_typo_100k` | 79.96 ms | 81.55 ms (1.02x) | 82.53 ms (1.03x) |\n| `unresolved_same_length` (whole file) | 48.10 ms | 48.22 ms (1.00x) | 47.49 ms (0.99x) |\n| `real_unknown` | 32.59 ms | 32.75 ms (1.00x) | 31.77 ms (0.97x) |\n| `real_typo` | 24.69 ms | 24.75 ms (1.00x) | 24.29 ms (0.98x) |\n| `nested_scopes_16_deep` (whole file) | 4.58 ms | 4.52 ms (0.99x) | 4.69 ms (1.02x) |\n| `suggestion_small_scope` | 139 us | 146 us (1.05x) | 146 us (1.05x) |\n\nEvery case that checks the file itself is flat, and correctly so: the errors are\nkept there, so the search still has to run. `discarded_errors` is the one that\nmoves. It checks the same file below `Require::Errors`, where the module is\nstill bound and its unresolved names are still found, but nothing it reports\nwill ever be read. Its unresolved names are module-level exports, which a\nsilenced module still solves, so the lookup is genuinely reached rather than\nskipped for want of a demand -- before this change it cost what checking the\nfile costs, and now it costs almost nothing. The search is not made faster\nthere; it stops happening.\n\nReviewed By: rchen152\n\nDifferential Revision: D117083070\n\nfbshipit-source-id: 8011df6991186e05a77cdc94e47a1e2f33ba2325\n"
    },
    {
      "commit": "0fd32921747715f8e8094544385510c0a643afc6",
      "tree": "d09f85280b89693759a46c34800b358bded8c09e",
      "parents": [
        "4ed5271868a7a26370cf78d7ea8e1df86baa0d8b"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Wed Aug 26 14:34:13 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 14:34:13 2026 -0700"
      },
      "message": "Express the scope walk as an iterator\n\nSummary:\n`visit_scopes` drove a callback while carrying two barrier values across\niterations and skipping class bodies that the current scope cannot see. That is\nan iterator written as a fold, and the callback shape means a caller wanting the\nscopes for anything other than a search has to invert its own logic to fit.\n\n`ScopeViews` is the same traversal as an `Iterator`, and `visit_scopes` becomes a\n`find_map` over it. The scoping rules and the barrier bookkeeping move with it, so\na caller still cannot see a class body from a nested code block without knowing\nthat rule exists.\n\nThe barriers are advanced after each view is built rather than before, because\nthey describe what lies between the *next* scope and the current one. That was\nimplicit in the old loop\u0027s ordering and is now stated.\n\n| benchmark | current | baseline |\n|---|---:|---:|\n| `real_long_typo` | 167.71 ms | 168.01 ms (1.00x) |\n| `unresolved_long` (whole file) | 137.37 ms | 139.07 ms (1.01x) |\n| `discarded_errors` (whole file) | 138.22 ms | 136.57 ms (0.99x) |\n| `unresolved_spread` (whole file) | 101.54 ms | 101.97 ms (1.00x) |\n| `suggestion_typo_100k` | 81.55 ms | 82.53 ms (1.01x) |\n| `unresolved_same_length` (whole file) | 48.22 ms | 47.49 ms (0.98x) |\n| `real_unknown` | 32.75 ms | 31.77 ms (0.97x) |\n| `real_typo` | 24.75 ms | 24.29 ms (0.98x) |\n| `nested_scopes_16_deep` (whole file) | 4.52 ms | 4.69 ms (1.04x) |\n| `suggestion_small_scope` | 146 us | 146 us (1.00x) |\n\nNothing moves, which is the point: this is a refactor of the traversal, not\nof the search.\n\nReviewed By: rchen152\n\nDifferential Revision: D117083073\n\nfbshipit-source-id: 85415fc132880ca5bf1f218624a00752ff9f79c8\n"
    },
    {
      "commit": "4ed5271868a7a26370cf78d7ea8e1df86baa0d8b",
      "tree": "08709b3d057e745b6641d7f1dfcb33713eecbe2b",
      "parents": [
        "6777beeaf913b68eb302ae525f5ac58d59588572"
      ],
      "author": {
        "name": "Sam Goldman",
        "email": "samgoldman@meta.com",
        "time": "Wed Aug 26 14:34:13 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 14:34:13 2026 -0700"
      },
      "message": "Benchmark the unknown-name suggestion search\n\nSummary:\nWhen a name does not resolve, Pyrefly looks for something close enough to\nsuggest. That search had no benchmark, and it is capable of dominating a file\u0027s\nwhole check: on machine-generated sources it can take longer than everything\nelse put together.\n\nEach case is one `best_suggestion` call shaped like the real one -- the names in\nscope innermost first, then the builtins, which every lookup pays for however\nsmall the file. The scope is 100,000 names and the missing name is twelve\ncharacters.\n\nThree scope shapes, because the cost turns on how candidate lengths sit relative\nto the missing name rather than on how many candidates there are:\n\n- `long_names`, where the scope is full of generated forty-character symbols, so\n  a length check can dismiss nearly all of them;\n- `spread`, ordinary source, where lengths vary and part of the scope has to be\n  measured properly;\n- `same_length`, where every candidate is exactly as long as the missing name and\n  nothing can be dismissed on length at all.\n\nTwo more for paths that behave differently: `typo`, where a match is found early\nand can tighten the search, and `small_scope`, which is what almost every real\nlookup looks like -- a handful of local names with the builtins behind them.\n\nThese are the baseline the rest of the stack is measured against:\n\n| benchmark | baseline |\n|---|---:|\n| `real_long_typo` | 168.01 ms |\n| `unresolved_long` (whole file) | 139.07 ms |\n| `discarded_errors` (whole file) | 136.57 ms |\n| `unresolved_spread` (whole file) | 101.97 ms |\n| `suggestion_typo_100k` | 82.53 ms |\n| `unresolved_same_length` (whole file) | 47.49 ms |\n| `real_unknown` | 31.77 ms |\n| `real_typo` | 24.29 ms |\n| `nested_scopes_16_deep` (whole file) | 4.69 ms |\n| `suggestion_small_scope` | 146 us |\n\nReviewed By: ndmitchell, rchen152\n\nDifferential Revision: D117083075\n\nfbshipit-source-id: 58cb7a7882438b932f955641e5854fe0ef8d22a3\n"
    },
    {
      "commit": "6777beeaf913b68eb302ae525f5ac58d59588572",
      "tree": "92e322a53a40aa32e0e4daaad48d8722eb305e25",
      "parents": [
        "ab8b949f959603d16da5f5050c5336f179121c49"
      ],
      "author": {
        "name": "Asuka Minato",
        "email": "i@asukaminato.eu.org",
        "time": "Wed Aug 26 13:46:44 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 13:46:44 2026 -0700"
      },
      "message": "fix pyrefly takes more than 1000 seconds to type check a simple script... #4678 (#4681)\n\nSummary:\nFixes https://github.com/facebook/pyrefly/issues/4678\n\nThe string-range collector now uses direct line lookup instead of repeatedly scanning huge non-ASCII lines to calculate unused columns, eliminating quadratic behavior.\n\nwith help from gpt 5.6 sol high\n\nPull Request resolved: https://github.com/facebook/pyrefly/pull/4681\n\nTest Plan: add test\n\nReviewed By: rchen152\n\nDifferential Revision: D117556529\n\nfbshipit-source-id: dbc21857e4e48c13d740279f220dc84c77e6afae\n"
    },
    {
      "commit": "ab8b949f959603d16da5f5050c5336f179121c49",
      "tree": "aea2fc134050659727eb478cd9daae4bb457c179",
      "parents": [
        "c6e50d8dfe245ea5fe6154381d4b54a2f7a7687d"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Wed Aug 26 12:59:51 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 12:59:51 2026 -0700"
      },
      "message": "Build numpy stubs package in GitHub CI\n\nSummary:\nThe previous diff added the `pyrefly-numpy-stubs` package metadata but nothing builds it. Teach the shape stubs workflow to build, smoke test, and verify the numpy package alongside `pyrefly-shape-extensions` and `pyrefly-torch-stubs`, so it ships with the rest of the release.\n\nThe version-stamping step previously had one hand-written block per package. A third copy would have been the same eight lines again, so this collapses them into a `stamp()` helper parameterized by build directory and by whether the package pins `pyrefly-shape-extensions`. Behavior for the two existing packages is unchanged.\n\nNote that publishing needs a one-time PyPI setup that is not part of this diff: `pyrefly-numpy-stubs` must have a pending trusted publisher registered for workflow `publish_shape_stubs.yml` and environment `pypi-shape-extensions`. `publish_shape_stubs.yml` uploads the whole `shape-stubs-dist` directory with `skip-existing: false`, so without that registration the upload would 403 and take the existing torch and shape-extensions publishes down with it.\n\nReviewed By: avikchaudhuri\n\nDifferential Revision: D117271675\n\nfbshipit-source-id: 7cb1a85dd99bebf18157839fe939e43d67523822\n"
    },
    {
      "commit": "c6e50d8dfe245ea5fe6154381d4b54a2f7a7687d",
      "tree": "53fddbadb05080997c762c9f1254189ab22dcfe2",
      "parents": [
        "b517b384bbda05cb67bb35ffd5139771249c5e16"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Wed Aug 26 12:59:51 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 12:59:51 2026 -0700"
      },
      "message": "Add package metadata for the NumPy and JAX stubs (#4658)\n\nSummary:\nPull Request resolved: https://github.com/facebook/pyrefly/pull/4658\n\nUsers have asked for the shape-aware NumPy stubs to be installable from PyPI, the way `pyrefly-torch-stubs` already is. Today the only way to get them is to copy the `tensor-shapes/` directory into your project.\n\nAdd the standalone `pyrefly-numpy-stubs` package metadata and PEP 561 marker so the stubs can be built as a pure-Python stub-only wheel and sdist. This mirrors `pyrefly-torch-stubs` exactly: the package installs only the `numpy-stubs` tree and depends on the matching `pyrefly-shape-extensions` version.\n\nBecause the distribution ships `numpy-stubs/` rather than `numpy/`, it is a PEP 561 stub package for the runtime `numpy` distribution and never shadows NumPy itself, so it can be co-installed with real NumPy.\n\nThe same metadata is added for `pyrefly-jax-stubs`, so the three stub packages stay in step rather than the JAX one drifting until someone needs it. It is deliberately **not** added to `build_shape_stubs.yml`, and so is not published: the `pyrefly-jax-stubs` name on PyPI is already taken by someone else, and that needs to be resolved with them before we can release under it. The build and publish workflows enumerate their packages explicitly rather than globbing, so nothing picks this up implicitly; a later diff wires it in once the name question is settled. The `pyproject.toml` says as much at the top, so the omission does not read as an oversight.\n\nReviewed By: avikchaudhuri\n\nDifferential Revision: D117271678\n\nfbshipit-source-id: b219398c73517595f63193511659ebf2d140e45e\n"
    },
    {
      "commit": "b517b384bbda05cb67bb35ffd5139771249c5e16",
      "tree": "b5368897e733a02a9bff8cebe7503456edcedd52",
      "parents": [
        "bd8217b46e7408cc0c0c0df979a3bff1d9ae1ebf"
      ],
      "author": {
        "name": "Asuka Minato",
        "email": "i@asukaminato.eu.org",
        "time": "Wed Aug 26 12:43:38 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 12:43:38 2026 -0700"
      },
      "message": "fix go-to definition / hover includes the lhs in operators #1517 (#3022)\n\nSummary:\nFixes https://github.com/facebook/pyrefly/issues/1517\n\nThe operator-definition path now only activates when the cursor is actually in the operator gap, instead of anywhere inside the enclosing expression, so hovering or go-to-def on the left 1 in 1 + 1 no longer resolves `int.__add__`.\n\nPull Request resolved: https://github.com/facebook/pyrefly/pull/3022\n\nTest Plan: update test\n\nReviewed By: stroxler\n\nDifferential Revision: D114358706\n\nfbshipit-source-id: cb641d4d9dbcdf7b5e31e0a6422fe5a912b59868\n"
    },
    {
      "commit": "bd8217b46e7408cc0c0c0df979a3bff1d9ae1ebf",
      "tree": "f64030b2dde45484cf962677770d4356b8afcb49",
      "parents": [
        "d76fdb9e1004eb37bc9fc1386ec94115940d4d0b"
      ],
      "author": {
        "name": "David Tolnay",
        "email": "dtolnay@meta.com",
        "time": "Wed Aug 26 11:55:30 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 11:55:30 2026 -0700"
      },
      "message": "Update tikv-jemallocator from 0.6.1 to 0.7.0\n\nSummary:\nRelease notes:\nhttps://github.com/tikv/jemallocator/blob/main/CHANGELOG.md\n\nReviewed By: stroxler\n\nDifferential Revision: D117526752\n\nfbshipit-source-id: b726b296cd30429857a6b515ca44f8611d41f335\n"
    },
    {
      "commit": "d76fdb9e1004eb37bc9fc1386ec94115940d4d0b",
      "tree": "40cbc9734cc261ac909eaf488784bf02e3d4c5b2",
      "parents": [
        "f60892c28268e17b2daba7ca72bda943f70742ae"
      ],
      "author": {
        "name": "cakeni",
        "email": "211545599+cakeni@users.noreply.github.com",
        "time": "Wed Aug 26 11:20:12 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 11:20:12 2026 -0700"
      },
      "message": "Resolve nested class forward references in annotations (#4513)\n\nSummary:\nAllow postponed and quoted annotations in a class body to resolve a nested class declared later in that same body. The deferred class-body lookup now records whether same-class forward resolution is legal, while ordinary runtime reads keep the existing inherited-only behavior.\n\nTests cover the future-annotations regression on Python 3.13, both annotations before and after the nested class declaration, and a runtime read that must still report unknown-name.\n\nFixes https://github.com/facebook/pyrefly/issues/4410\n\nPull Request resolved: https://github.com/facebook/pyrefly/pull/4513\n\nTest Plan:\n- cargo +stable-x86_64-pc-windows-gnu test -p pyrefly --lib test_nested_class_ -- --nocapture (9 passed)\n- python test.py --no-test --no-tensor-shapes --no-conformance --no-jsonschema\n- cargo fmt --all -- --check\n- git diff --check\n\nReviewed By: samwgoldman\n\nDifferential Revision: D115588128\n\nPulled By: fangyi-zhou\n\nfbshipit-source-id: 9d7f6f7e505ced19d15f6cdfa5fae22284f3bb8c\n"
    },
    {
      "commit": "f60892c28268e17b2daba7ca72bda943f70742ae",
      "tree": "e7adf31dc588eefc441e68beb9e319a3e235755f",
      "parents": [
        "bff26f44fbe0202916cb73fe8a858d3a506515b9"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Wed Aug 26 10:33:40 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 10:33:40 2026 -0700"
      },
      "message": "Move Torch creation shapes to direct `IntTuple` parameters\n\nSummary: Torch creation and target-shape APIs only project an input size or an existing tensor shape, so routing them through V1 shape functions adds machinery without adding semantics. Express these operations directly with `IntTuple`-bounded type parameters while preserving their overload surfaces and precedence rules. This keeps literal, symbolic, gradual, empty, and open shapes precise and removes four fully retired V1 shape functions.\n\nReviewed By: rchen152\n\nDifferential Revision: D113620585\n\nfbshipit-source-id: c3c02eca10dcb00b011f2f000290bd9323a719a2\n"
    },
    {
      "commit": "bff26f44fbe0202916cb73fe8a858d3a506515b9",
      "tree": "e8677cc488ed7931b1ecd985e3b30eb0d520d02b",
      "parents": [
        "5b28564ea3b7265d7d760cc0ef8333219ab87b4b"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Wed Aug 26 10:14:52 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 10:14:52 2026 -0700"
      },
      "message": "Preserve tuple shapes for IntTuple-bounded type variables\n\nSummary:\nType variables bounded by `IntTuple` represent an entire tensor shape. Ordinary type-variable inference widens implicit integer literals, and converting an arbitrary tuple to a shape can otherwise hide invalid elements.\n\nRecognize these parameters from their resolved upper bound, validate tuple arguments structurally, and bind their elements through the existing dimension solver. This preserves literal and symbolic dimensions, keeps repeated constraints consistent, and leaves ordinary type-variable inference unchanged.\n\nThis prepares constructor calls such as `torch.zeros((3, 4))` to retain the precise shape `IntTuple[3, 4]`.\n\nReviewed By: avikchaudhuri\n\nDifferential Revision: D113618920\n\nfbshipit-source-id: aa65962d2da937a481ed37dab29ce654a4bcbbbe\n"
    },
    {
      "commit": "5b28564ea3b7265d7d760cc0ef8333219ab87b4b",
      "tree": "2819c3ab50ed657f78bcc0c7a31d0207c6e62490",
      "parents": [
        "e6561bbdbf913014fc208c7f458b8973a113f064"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Wed Aug 26 10:14:52 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 10:14:52 2026 -0700"
      },
      "message": "Migrate functional convolution shape rules to V2\n\nSummary:\nFunctional convolution and transposed convolution still depended on the legacy shape interpreter, preventing their formulas from using the typed shape DSL. Move all six operations to shared V2 helpers that preserve scalar expansion, symbolic arithmetic, gradual inputs, and the existing permissive channel and group behavior.\n\nPublic parameter tuples retain their rank-specific cardinality, so 1D, 2D, and 3D APIs reject empty, short, or overlong tuples before evaluation. Fixed public `Flag` domains flow into the shared unbounded helper domain through the fixed-to-unbounded subset relation. Forward convolution diagnoses mismatched input and weight ranks; transposed convolution retains the legacy low-rank behavior and accounts for `groups` when computing output channels.\n\nReviewed By: yangdanny97\n\nDifferential Revision: D113609341\n\nfbshipit-source-id: bfe9dcb4b114d0fbad0a2b3aafd4ae83fef1d79b\n"
    },
    {
      "commit": "e6561bbdbf913014fc208c7f458b8973a113f064",
      "tree": "67f592952c557cf1d9152dd4250a357dc11ee260",
      "parents": [
        "ee9a4f85f9242e5c12786fee44770f5efae7d9bc"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Wed Aug 26 10:14:52 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 10:14:52 2026 -0700"
      },
      "message": "Support fixed tuple Flag domains\n\nSummary:\nThis diff extends `Flag` domains to preserve the arity of fixed integer tuples, which convolution parameters need for precise helper composition.\n\nScalar members use explicit boolean fields, while the tuple member distinguishes absent, fixed-arity, and unbounded integer tuples. Domain parsing rejects unions of conflicting fixed arities unless the author explicitly includes `tuple[int, ...]`. Assignability allows a fixed tuple domain to flow into an unbounded tuple domain, but not the reverse.\n\nThe ordinary type-system boundary materializes fixed domains as concrete tuple types, while DSL validation and helper calls use the same subset relation. Tests cover literal solving, defaults, gradual and unpacked tuples, constructor lookup, and helper composition in both directions.\n\nReviewed By: avikchaudhuri\n\nDifferential Revision: D113607815\n\nfbshipit-source-id: 9b3051cd4e42844920241cec365474d66fb71108\n"
    },
    {
      "commit": "ee9a4f85f9242e5c12786fee44770f5efae7d9bc",
      "tree": "109ee87a27251dc8c50c5e4b205a1552f75047ba",
      "parents": [
        "cedb4ef5f3cc96e9b82633be473072f63ab7516c"
      ],
      "author": {
        "name": "Asuka Minato",
        "email": "i@asukaminato.eu.org",
        "time": "Wed Aug 26 08:57:28 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 08:57:28 2026 -0700"
      },
      "message": "fix enum.Flag unions incorrectly do not match typing.self in (class)methods. #4657 (#4675)\n\nSummary:\nFixes https://github.com/facebook/pyrefly/issues/4657\n\nfixes enum.Flag unions being incorrectly rejected as typing.Self return values, recognizes member-bearing enums as non-subclassable.\n\nPull Request resolved: https://github.com/facebook/pyrefly/pull/4675\n\nTest Plan: add test\n\nReviewed By: stroxler\n\nDifferential Revision: D117490603\n\nfbshipit-source-id: 508b8ab5306933b3f44180b3ae1fe3581b601753\n"
    },
    {
      "commit": "cedb4ef5f3cc96e9b82633be473072f63ab7516c",
      "tree": "559f710adc8eb87713d633cfb93721f725fabf2e",
      "parents": [
        "c0047d8413bb1b9b3dc26046317855bbc97d27be"
      ],
      "author": {
        "name": "Steven Troxler",
        "email": "stroxler@meta.com",
        "time": "Wed Aug 26 08:52:31 2026 -0700"
      },
      "committer": {
        "name": "meta-codesync[bot]",
        "email": "215208954+meta-codesync[bot]@users.noreply.github.com",
        "time": "Wed Aug 26 08:52:31 2026 -0700"
      },
      "message": "Represent Flag domains with explicit members\n\nSummary:\n`FlagDomain` has only five possible members, so a bitset obscures the representation without providing a meaningful performance benefit. Store membership as explicit fields instead.\n\nThis keeps the domain compact and `Copy`, while making construction, union, and membership checks direct. It also gives later changes a straightforward place to replace tuple membership with structured tuple information.\n\nReviewed By: avikchaudhuri\n\nDifferential Revision: D117307800\n\nfbshipit-source-id: c38056eaa5ad2118d813680444d765822b1879a0\n"
    }
  ],
  "next": "c0047d8413bb1b9b3dc26046317855bbc97d27be"
}
