[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-meta-add-shape-types-to-torch-model":3,"mdc--f42yxi-key":53,"related-org-meta-add-shape-types-to-torch-model":4476,"related-repo-meta-add-shape-types-to-torch-model":4656},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":12,"stars":26,"repoUrl":27,"updatedAt":28,"license":29,"forks":30,"topics":31,"repo":48,"sourceUrl":51,"mdContent":52},"add-shape-types-to-torch-model","annotate PyTorch models with tensor shapes","Port a PyTorch model to use pyrefly's tensor shape type system (Tensor[[B, C, H, W]], Int[T]). Use this skill whenever the user wants to add shape annotations to a PyTorch model, type a model with tensor dimensions, port a model to use shape tracking, or annotate model forward methods with tensor shapes. Also use when the user mentions tensor shape ports, Int types for PyTorch, or pyrefly shape checking on a model file. Invoke BEFORE starting any model port — the skill's gated workflow prevents common failure modes.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},"meta","Meta Open Source","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fmeta.png","facebook",[13,17,20,23],{"name":14,"slug":15,"type":16},"Deep Learning","deep-learning","tag",{"name":18,"slug":19,"type":16},"PyTorch","pytorch",{"name":21,"slug":22,"type":16},"Data Modeling","data-modeling",{"name":24,"slug":25,"type":16},"Python","python",6833,"https:\u002F\u002Fgithub.com\u002Ffacebook\u002Fpyrefly","2026-07-18T05:12:08.515952",null,461,[32,33,34,35,36,25,37,38,39,40,41,42,43,44,45,46,47],"code-quality","ide","language-server","language-server-protocol","lsp","rust","type-annotations","type-check","type-checker","type-hints","typecheck","typechecker","typechecking","types","typing","vscode-extension",{"repoUrl":27,"stars":26,"forks":30,"topics":49,"description":50},[32,33,34,35,36,25,37,38,39,40,41,42,43,44,45,46,47],"A fast type checker and language server for Python","https:\u002F\u002Fgithub.com\u002Ffacebook\u002Fpyrefly\u002Ftree\u002FHEAD\u002Ftensor-shapes\u002Fskills\u002Fadd-shape-types-to-torch-model","---\nname: add-shape-types-to-torch-model\ndescription: >\n  Port a PyTorch model to use pyrefly's tensor shape type system (Tensor[[B, C, H, W]],\n  Int[T]). Use this skill whenever the user wants to add shape annotations\n  to a PyTorch model, type a model with tensor dimensions, port a model to use shape\n  tracking, or annotate model forward methods with tensor shapes. Also use when the\n  user mentions tensor shape ports, Int types for PyTorch, or pyrefly shape checking\n  on a model file. Invoke BEFORE starting any model port — the skill's gated workflow\n  prevents common failure modes.\n---\n\nYou are porting a PyTorch model to use pyrefly's tensor shape type system.\n\n**The methodology below is mandatory; how much you write down depends on the\njob.** Each step has an artifact — an audit table, a per-local `reveal_type`\ndump, a typed-interface receipt, an `assert_type` count. Working through them in\norder is not optional: the next step's input is the previous step's output, and\nskipping a step means substituting reasoning for testing, which is the primary\nfailure mode.\n\nWhat varies is the *deliverable*:\n\n- **Annotating someone's own model** (the common case): do every step as internal\n  reasoning, but what you hand back is the annotated model plus a short report of\n  what couldn't be tracked. You don't need to paste every table — the \"paste this\"\n  instructions below are for the contribution case.\n- **Contributing a reference example** (e.g. into a maintained example corpus):\n  the tables, receipts, and counts ARE part of the deliverable — paste them in\n  full, because others read these ports to learn the patterns. A skill that\n  invokes this one for corpus work will say so; absent that, assume the lighter\n  deliverable.\n\n# Before you start: two questions\n\nResolve these with the user before Gate 0. In the common case these are the only\ntwo times you interrupt them:\n\n1. **Confirm how you'll check, and where the stubs are.** State it operationally —\n   e.g. \"I'll type-check with `\u003Ccommand>` against the shape stubs at `\u003Cpath>`,\n   correct?\" — and let the user confirm or correct. Don't make them reason about\n   internal concepts; just confirm a command and a location. Default the command\n   to `pyrefly check` (assume `pyrefly` is on `PATH`, however it was installed) and\n   discover where the stubs live from `pyrefly dump-config`, which prints the\n   resolved search path. If a skill invoked this one, it may supply both instead\n   (for example, an in-repo build-and-check command).\n2. **Ask whether they're open to changing the stubs.** Adding or refining a stub\n   signature can recover shapes an op would otherwise lose.\n   - **No** (or unsure): don't touch the stubs. Port the model as well as the\n     existing stubs allow, collect what couldn't be tracked, and report it at the\n     end (see Completion report), suggesting an upstream issue for the gaps worth\n     closing. This path is fully supported — a less-complete port is the expected\n     outcome here, not a failure.\n   - **Yes**: you have standing permission to make straightforward stub-signature\n     improvements as you go. Don't re-ask per op. Still port first and confirm the\n     gap with `reveal_type` before editing a stub.\n\nDon't ask about deeper changes (teaching Pyrefly new shape *logic*) up front —\nthat comes up only reactively, and rarely (see \"When an op's shape is wrong\").\n\n# Pre-flight\n\n**Create tasks** for each gate and the module loop\u002Fverification phases\nthat follow. Update them as you complete each stage — this gives\nvisibility during long-running ports.\n\nComplete these gates before writing any code.\n\n## Gate 0: Understand the system\n\nRead `shape_tracking_capabilities.md` (this skill dir). It explains the\nthree shape-tracking mechanisms (shape-aware stubs, DSL functions, special\nhandlers) and how to check each one, plus the current `shape_extensions` API\nsurface (`Int` \u002F `IntVar` \u002F `IntTuple` \u002F `Elements` \u002F `assert_shape` \u002F runtime\ncompat) and the double-bracket `Tensor[[...]]` convention. You need this context\nto make the Gate 1 audit meaningful — knowing whether an op exists in a stub is\nnot the same as knowing whether its shapes are tracked.\n\n**Do NOT read `style_guide.md` yet.** It is comparison material for the\nverification phase. Reading it now biases you toward known patterns\nbefore you have empirically probed this model's shapes.\n\n## Gate 1: Audit ops\n\nList every `nn.Module` subclass and `torch`\u002F`F.` function called in the\nmodel. Check each against the shape-aware torch stubs (the `.pyi` files under the\nstub root you confirmed up front — `pyrefly dump-config` reports it) and any shape\nDSL declarations in those stubs. The stubs attach DSL shape functions with\n`@uses_shape_dsl(ir_fn)`, and the IR functions live in `_shapes.pyi` next to the\nstubs, imported from stub files as `torch._shapes` because the stub package\nprovides the `torch` package for type checking. This is a **diagnostic** pass — you are recording\nwhich ops are tracked and which aren't, not fixing anything. A gap here never\nblocks the port. This step should take minutes — you are scanning the stub file\nfor the op and, only when a decorator points there, the corresponding IR\nfunction.\n\n**Do NOT delegate this audit to code search agents or use web search for this\nstep.** The torch-stubs package and its `_shapes.pyi` DSL\nfile are exhaustive for torch shape support. For each op in your list, check\nwhether it appears in the relevant stub file and whether it has a precise\ngeneric signature, `Self`\u002F`Tensor[S]` (whole-shape `S: IntTuple`) return, or `@uses_shape_dsl(...)`\ndecorator that refines a bare declared return. Use targeted file reads or\nrepo-approved search scoped to known files\u002Fdirectories, not broad recursive\nshell search. You need to confirm presence and spot missing attributes\n(e.g., `bias` on `Conv2d`), not memorize every signature.\n\n**Paste your audit table** in your response before proceeding to Gate 2:\n\n```\n## Gate 1: Ops audit\n| Op | Stub location | Shape DSL decorator \u002F IR fn (or \"no decorator\") | Status |\n|----|---------------|------------------------------|--------|\n| nn.Conv2d | tensor-shapes\u002Fpyrefly-torch-stubs\u002Ftorch-stubs\u002Fnn\u002F__init__.pyi — generic [InC,OutC,K,S,P,D] | no decorator (stub generic) | tracked-stub |\n| F.adaptive_avg_pool2d | tensor-shapes\u002Fpyrefly-torch-stubs\u002Ftorch-stubs\u002Fnn\u002Ffunctional.pyi — bare declared return | `@uses_shape_dsl(adaptive_pool_ir)`, defined in `_shapes.pyi` | tracked-DSL |\n| ...\n```\n\nStatus is one of `tracked-stub`, `tracked-DSL`, `tracked-handler` (a special\nhandler tracks it), or `GAP` (no shape support found).\n\nFilling the \"Shape DSL decorator \u002F IR fn\" column requires checking whether\nthe stub declaration has a `@uses_shape_dsl(...)` decorator. If it does,\nconfirm the named IR function exists in `_shapes.pyi` next to the stubs.\nWrite \"no decorator\" only after confirming the stub declaration has no\ndecorator — do not leave this column blank or write \"check DSL\".\n\nA `GAP` is information, not a blocker — note it and move on. You decide what to do\nabout gaps later: most degrade gracefully to a bare `Tensor`, and only if the user\nopted into stub changes is a `GAP` worth a stub fix.\n\n## Gate 2: Inventory the original\n\nWrite the inventory as a comment block at the top of the port file, using\nthis exact format:\n\n```python\n# ## Inventory\n# - [ ] ClassName.__init__ — Int: param1, param2; int: param3\n# - [ ] ClassName.forward\n# - [ ] function_name — utility, no tensors\n# ...\n```\n\n**Every class, function, and method in the original file must appear, and\nevery item must be ported.** Do not skip or exclude anything. If a class\ndepends on a library without shape-aware stubs, port it anyway — its tensors\nfall back to bare `Tensor`, which is acceptable; record the gap for the report.\nOnly if the user opted into stub changes, and a minimal stub for the specific\nops used would recover real shapes, is adding one worthwhile.\n\nFor each class, list constructor parameters and whether each is Int or\nint — this feeds Step 1 of the module loop.\n\n**Check off items as you port them** (`[ ]` → `[x]`). Do not proceed to\nverification with unchecked items.\n\n# Transition to module loop\n\nYou have completed pre-flight. You have NOT written any model code yet.\n\n**Your analysis so far is a hypothesis.** The module loop tests it\nempirically. If you catch yourself planning multiple modules' forwards\nin your head, STOP — you are substituting reasoning for testing, and\nreasoning is less reliable.\n\nWrite the file with imports, the inventory comment, and utility functions\n(no tensor shapes). Then start Step 1 for the FIRST module only.\n\nRead `porting_principles.md` (this skill dir) for the mindset: why we port,\npriority order, and stub philosophy.\n\n# Module loop\n\n**Repeat the following for each module in dependency order.** Each module's\ntyping may inform the next — e.g., discovering that a submodule tracks\nshapes internally changes how the parent handles its loop.\n\n**ONE MODULE AT A TIME.** Complete Steps 1–6 for module A, paste the\nStep 6 checklist, THEN start Step 1 for module B. If you find yourself\ntyping two modules' constructors before running the checker, you have\nalready entered the primary failure mode: writing the entire file and\nvalidating at the end leads to over-use of typed interfaces and under-use\nof `assert_type`.\n\n## Step 1: Inventory parameters\n\nList every constructor parameter. For each, decide:\n- **Int**: the value determines a tensor dimension (flows to `nn.Linear`,\n  `nn.Conv2d`, tensor creation, or any typed function that uses the value\n  as a shape dimension).\n- **int**: iteration count (`n_layers`, `n_res_block`) or boolean-like flag.\n\nIf in doubt, make it `Int`. The cost is one more type param; the cost of\n`int` is permanent shape loss in everything downstream.\n\n**Critical rules:**\n- Every `int` that flows to a sub-module constructor (`nn.Linear(dim, ...)`)\n  MUST be `Int`. No exceptions.\n- Never cast Int to int (`int(dim)`, `self.x = int(dim)`) — `Int` is a\n  subtype of `int`, so the cast only kills tracking. Exception:\n  `bool`\u002F`float` conversion is necessary, but `int * Int` produces\n  Unknown — check whether it reaches tensor shapes before fixing. Don't\n  replace with if\u002Felse branching (union of concrete expressions is worse\n  than one Unknown).\n- Derived dims use expressions (`D \u002F\u002F NHead`, `4 * ES`), not independent\n  type params. Only independent degrees of freedom get type params.\n- **Dimensions from `list[int]`.** `list[int]` element access (e.g.,\n  `hidden_units[-1]`) erases the concrete value to `int`. Add an explicit\n  `Int` field to the config or constructor for that value.\n- Use `nn.Buffer` and `nn.Parameter`, not `register_buffer`\u002F\n  `register_parameter`.\n- **Bridge dims.** When part of the model is untracked (e.g., features\n  built via `nn.Sequential(*list)`), look for dimensions that connect\n  the untracked section to tracked downstream modules. For example, if\n  features output feeds a Linear classifier, the Linear's `in_features`\n  is a bridge dim — making it a class type param enables annotation\n  fallback to recover a shaped type (e.g., `Tensor[[B, LastC]]`) that\n  then flows naturally through downstream ops. Without it, annotation\n  fallback can only recover bare `Tensor` or batch-only shapes.\n\n  ```python\n  class Model[NC: IntVar, LC: IntVar](nn.Module):\n      def __init__(self, num_classes: Int[NC] = 1000,\n                   last_channel: Int[LC] = 1280):\n          ...\n          self.classifier = nn.Linear(last_channel, num_classes)\n  ```\n\n  Here `LC` bridges the untracked feature extractor to the typed\n  classifier, recovering `Tensor[[B, NC]]` at the output.\n- **`Int[X] | None` for optional dimensions.** When a parameter is\n  `Optional[int]` but flows to tensor shapes when present, type it as\n  `Int[X] | None`, not `Optional[int]`. Example:\n  `rank_k: Optional[int]` → `rank_k: Int[RK] | None`. In the forward\n  method, narrow with `if rank_k is not None:` — the checker then\n  treats `rank_k` as `Int[RK]` inside the branch. Leaving it as\n  `Optional[int]` permanently loses tracking in every downstream op.\n- **Parameterized config dataclasses.** When multiple modules consume\n  dimensions from the same `@dataclass` config, note it — Step 2\n  shows how to parameterize the config so dims propagate across\n  module boundaries.\n- **Lazy-initialized buffer attributes.** An attribute's type is fixed\n  at the declaration, not at later assignments. Declaring\n  `self.x: Tensor | None = None` and assigning a real tensor in a\n  setup hook (e.g., `setup_caches`) loses the shape forever — every\n  read site sees `Tensor | None`, and the best you get after a None\n  check is bare `Tensor`. If the field is always assigned before\n  first use, initialize it eagerly in `__init__` with the real shape:\n\n  ```python\n  # Bad: causal_mask is Tensor | None everywhere; shape is lost\n  class Attention(nn.Module):\n      def __init__(self, ...):\n          self.causal_mask: Tensor | None = None\n      def setup_caches(self, max_seq_len: int):\n          self.causal_mask = torch.tril(\n              torch.ones(max_seq_len, max_seq_len)\n          )\n\n  # Good: causal_mask is Tensor[[MS, MS]] from declaration\n  class Attention[MS: IntVar](nn.Module):\n      def __init__(self, max_seq_len: Int[MS], ...):\n          self.causal_mask: Tensor[[MS, MS]] = torch.zeros(\n              max_seq_len, max_seq_len\n          )\n  ```\n\n  Reserve `Tensor | None` for fields that may *genuinely* never be\n  set. If late init is unavoidable because the shape depends on a\n  runtime decision, accept that bare `Tensor` post-narrow is the\n  right answer and document it as a Step 4 receipt.\n\n## Step 2: Type the constructor\n\nWrite `__init__` with the `Int` params from Step 1. Construct sub-modules\nusing those Int params — they get typed automatically.\n\n**Default values for Int params:** `Literal[0]` is not assignable to\n`Int[X]` as a default. Use PEP 696 type-parameter defaults instead:\n\n```python\n# Won't work — Literal[1000] not assignable to Int[NC]:\ndef __init__(self, num_classes: Int[NC] = 1000): ...\n\n# Works — NC defaults to 1000 at the type level (bound + PEP 696 default):\nclass Model[NC: IntVar = 1000](nn.Module):\n    def __init__(self, num_classes: Int[NC] = 1000): ...\n```\n\n**Constructor patterns that break shape tracking:**\n- **`nn.Sequential(*list_var)`** erases module types — the Sequential\n  returns bare `Tensor`. Only `nn.Sequential(M1(), M2(), M3())` with\n  direct arguments is tracked. Extract shape-changing modules (Linear,\n  Conv2d) as individual attributes and chain in `forward`.\n- **Factory functions returning `nn.Sequential`** erase all type\n  parameters at the function boundary. Use a class with a typed\n  `forward` method instead.\n- **`getattr(nn, name)()`** returns `Any`. Replace with a union of\n  typed `nn.Module` subclass types.\n- **Method-level type params on class fields.** If a method creates\n  shaped tensors assigned to `self.field`, the field can't carry the\n  method's type params — it reverts to bare `Tensor`. Move creation\n  to `__init__` so type params become class-level.\n\n**Parameterized config dataclasses.** When a `@dataclass` holds\ndimension hyperparameters consumed by multiple modules, make it\ngeneric so dims propagate through constructors:\n\n```python\n@dataclass\nclass Config[D: IntVar, NHead: IntVar, VocabSize: IntVar]:\n    dim: Int[D]\n    n_head: Int[NHead]\n    vocab_size: Int[VocabSize]\n    dropout: float = 0.0\n```\n\nModules extract only the params they need using `Any` for the rest:\n\n```python\nclass MLP[D: IntVar](nn.Module):\n    def __init__(self, config: Config[D, Any, Any]):\n        super().__init__()\n        self.fc = nn.Linear(config.dim, 4 * config.dim)\n```\n\nWithout this, each module must independently accept and thread\nevery dim through its constructor — error-prone and verbose.\n\nIf the original config had default values (e.g., `dim: int = 768`),\ncombine the two patterns above — give the dataclass type params PEP\n696 defaults so callers can omit dims:\n\n```python\n@dataclass\nclass Config[D: IntVar = 768, NHead: IntVar = 12, VocabSize: IntVar = 50257]:\n    dim: Int[D] = 768  # type: ignore[bad-assignment]\n    n_head: Int[NHead] = 12  # type: ignore[bad-assignment]\n    vocab_size: Int[VocabSize] = 50257  # type: ignore[bad-assignment]\n    dropout: float = 0.0\n```\n\nTwo different defaults are at play here, and only one is clean:\n- The **PEP 696 defaults on the type params** (`[D: IntVar = 768, ...]`) are\n  what let callers omit dims — those need no ignore.\n- The **dataclass field literal defaults** (`dim: Int[D] = 768`) still need\n  `# type: ignore[bad-assignment]`, because a plain `int` literal is not\n  assignable to `Int[D]`. This is the accepted corpus pattern (see\n  `examples\u002Ffinalmlp.py`). Note that *constructor*-parameter defaults\n  (`def __init__(self, num_classes: Int[NC] = 1000)`) do **not** need the\n  ignore — only dataclass field defaults do.\n\nNow `Config()` produces `Config[768, 12, 50257]` and\n`Config(dim=1024)` produces `Config[1024, 12, 50257]` — dims\npropagate even when callers don't pass every parameter.\n\n**DO NOT write the forward method yet.** The forward signature and\n`assert_type` expressions depend on what the checker infers, which you\ndon't know until Step 3.\n\nRun the checker to verify the constructor compiles. **Paste the checker\noutput** (0 errors, or the errors you need to fix) before proceeding.\n\n## Step 3: Probe the forward\n\nFirst, **count the local variables** in the forward method — every\nassignment to a name (e.g., `x = ...`, `out = ...`, `result = ...`)\nis a local. Write them down.\n\nThen add `reveal_type` on EVERY local variable. Run the checker.\n\n**Paste the results in your response** using this exact format. Step 4\ntakes this table as input — if you don't have it, you cannot proceed.\n\n```\n# reveal_type results for ClassName.forward:\n# Locals: N (list them: var1, var2, var3)\n# var1 (line N): Tensor[[B, C, H, W]]  → SHAPED\n# var2 (line M): Tensor                 → BARE — investigate in Step 4\n# var3 (line P): Tensor[[B, D]]         → SHAPED\n```\n\nVerify: does the number of reveal_type entries match the local count?\nIf not, you missed some — go back and add them.\n\n**If a reveal_type result contradicts your understanding of the op**\n(e.g., spatial dims unchanged after a strided conv, or a shaped op\nreturning bare), write a small isolating test, run the checker, and\nconfirm the behavior before proceeding. Either your understanding is\nwrong (update your mental model) or the checker has a simplification\nyou should document.\n\nThis table is your Step 4 input. Do not write `assert_type` until Step 4\nis complete for every BARE entry. The results tell you:\n- Shaped type → the checker tracks this op. Write `assert_type` in Step 5.\n- Bare `Tensor` → shape lost. Investigate in Step 4 before deciding.\n\n## Step 4: Restructure for tracking\n\nMany patterns that LOOK dynamic have trackable substructure.\nConditional branching over matmul\u002Fbmm chains, for example, is fully\ntrackable if the dimension values are `Int`-typed.\n\nFor EACH bare `Tensor` from Step 3, attempt ALL applicable restructurings\nbefore falling back to typed interface:\n\n□ **`int()` or `round()` wrapping a Int value?** Remove it. If the\n  argument is already int-compatible (e.g., `round()` on an integer\n  `expand_ratio`), the wrapper is a no-op that kills tracking.\n\n□ **`nn.Sequential(*list_var)`?** Extract shape-changing modules\n  (Linear, Conv2d, etc.) as individual attributes and chain them in\n  `forward`. Shape-preserving modules (activations, norms, dropout)\n  can remain grouped since their output shape equals their input.\n  Note: this applies to `nn.Sequential(*list_variable)` where the\n  modules come from a list. `nn.Sequential(M1(), M2(), M3())` with\n  direct arguments IS tracked — don't restructure it.\n\n□ **`nn.Sequential` subclass?** The special handler tracks shapes when\n  a Sequential is CALLED as an attribute (`self.net(x)`), but NOT when\n  forward is inherited from a Sequential base class. Convert subclasses\n  to composition: replace `class Foo(nn.Sequential)` \u002F\n  `super().__init__(m1, m2, m3)` with `class Foo(nn.Module)` \u002F\n  `self.net = nn.Sequential(m1, m2, m3)` and delegate forward to\n  `self.net(x)`. This is the minimal change for full shape tracking.\n\n□ **`list[...]` where `tuple[...]` is needed?** `torch.cat([a, b])`\n  homogenizes element types. Use `torch.cat((a, b))`. Same for\n  `.split([d, k, k])` → `.split((d, k, k))`.\n\n□ **Branch join widening?** If the first iteration changes shape but\n  subsequent iterations preserve it, separate the first iteration:\n  `x = layers[0](input)` then loop over `layers[1:]`. The dual works\n  too: separate the last iteration if only the final output matters.\n\n□ **Loop over `ModuleList` widens tensor type?** Same fix as branch\n  join: separate the shape-changing iteration from shape-preserving ones.\n\n□ **Tensor accumulation for `stack`\u002F`cat`?** Type the list with the\n  element shape, then annotate the stack\u002Fcat result with the full shape\n  including the new dimension (the DSL can't infer collection size from\n  a dynamic loop).\n\n□ **Inlined expressions?** `f(g(x))` sometimes loses shapes that\n  `y = g(x); f(y)` preserves. Break into separate assignments.\n\n□ **Op genuinely missing from the stubs?** Confirm it's absent (check the stubs\n  and any `@uses_shape_dsl(...)` IR function they reference). A missing shape is\n  not a blocker — it degrades to a bare `Tensor` that you document below. If the\n  user opted into stub changes and a refined signature would recover the shape,\n  that's a fair fix. If instead Pyrefly computes a *wrong* shape, see \"When an\n  op's shape is wrong\".\n\n□ **About to claim an op is untracked?** Check the shape-aware stubs, their\n  `@uses_shape_dsl(...)` decorators and IR functions, and special handlers\n  first. The system tracks reshape, flatten, permute, transpose, cat, stack,\n  matmul, arange, zeros, outer, interpolate, einsum, and many more.\n\nAfter EACH restructuring, re-run `reveal_type` and update your records.\n\n**STOP before using typed interface.** For each bare variable where you\nwant typed interface, paste this filled-out receipt in your response:\n\n```\n## Typed interface receipt [\u003CModule>.\u003Cvar>]: \u003Cvariable> in \u003CClassName.forward>\n- int()\u002Fround() cast: [removed \u002F not applicable — reason]\n- Sequential(*list): [restructured \u002F not applicable — reason]\n- list→tuple: [not applicable — reason]\n- Branch join: [not applicable — reason]\n- Inlined expressions: [split \u002F not applicable — reason]\n- Missing stub\u002FDSL: [checked stubs + `@uses_shape_dsl` IR — reason]\n- Int | None reclassification: [reclassified param X \u002F not applicable — reason]\n- Bridge dim: [promoted X to class Int \u002F not applicable — reason]\n- Config parameterization: [parameterized Config[...] \u002F not applicable — reason]\nResult: still bare after all checks. Using typed interface because ___.\n```\n\nIf you cannot fill this out, you have not completed Step 4. Go back.\n\n\"Restructure\" usually means a 2–3 line change: separating an iteration,\nremoving an `int()` cast, or adding an `Int` type param. It does NOT mean\nrewriting the algorithm. If you find yourself writing significantly\ndifferent logic, you've gone too far. Even partial dim tracking (e.g.,\noutput dim only) is far more useful than none.\n\n**`type: ignore` categories.** Before writing `type: ignore`, identify\nwhich category applies:\n- **A1 algebraic gap** (`N * (X \u002F\u002F N) ≠ X`): no fix, use `type: ignore`.\n- **Conditional equality** (e.g., `Inp == Oup` at runtime but separate\n  type params): no fix, use `type: ignore`.\n- **Stub gap** (op missing, or its signature too loose to track): if the user\n  opted into stub changes, refining the stub signature is the fix; otherwise\n  document the bare result and move on. A *wrong* computed shape is a different\n  case — see \"When an op's shape is wrong\".\n- **`return-value` mismatch from untracked sub-section**: don't\n  `type: ignore`. The fix is upstream — find the bridge dim\n  connecting the untracked section (e.g., `nn.Sequential(*list)`\n  features) to the tracked downstream input (e.g., a classifier\n  Linear), promote it to a class type param per Step 1's bridge-dim\n  rule, then use annotation fallback to recover the shaped return.\n- **Branch join**: try restructuring first.\n\nOnce you've settled the category, use the specific error code (a bare\n`# type: ignore` is rejected). The codes seen across the corpus:\n- `bad-assignment` — a dataclass field literal default (`dim: Int[D] = 768`) or\n  a typed fallback assignment (`x: Tensor[[B, N]] = untracked_result`).\n- `arg-type` — passing a bare\u002Flooser value into a shaped parameter (common in\n  init\u002Fsetup helpers).\n- `assert-type` \u002F `bad-return` — an A1 algebraic gap where the computed shape\n  differs from the `assert_type`\u002Fdeclared-return shape.\n- `bad-argument-type`, `return-value` — the argument\u002Freturn variants of the\n  above; `return-value` from an untracked sub-section should be fixed upstream\n  (see the bridge-dim bullet), not ignored.\n\n**When an op's shape is wrong.** Everything above handles a *missing* shape (the\nop falls back to bare `Tensor`) — that always degrades gracefully and never\nblocks. The rare hard case is a *wrong* shape: Pyrefly computes a concrete shape\nthat is incorrect (e.g. integer floor-division where the real op rounds up). You\ncannot annotate around this — the checker actively disagrees with reality.\nWhen it happens, tell the user; fixing it means teaching Pyrefly new shape logic,\nnot editing a stub signature. If a shape-DSL skill (e.g. `modify-shaped-array-dsl`)\nis available, hand off to it; otherwise file an upstream issue describing the op\nand the correct rule, and document the spot with `type: ignore` for now. Don't\nreach for this on ordinary bare-`Tensor` gaps — only when a computed shape is\nprovably wrong.\n\n**Bare `Tensor` where you know the shape?** Use `assert_type` to verify\ninference, not annotation fallback. Annotation fallback silently accepts\nbare `Tensor` — it doesn't prove tracking works. If the checker can't\ninfer the shape, trace upstream to find where shapes were actually lost.\n\n## Step 5: Write forward and assert_type\n\n**Annotation hierarchy** (most to least desirable):\n1. **`assert_type`** — verifies the checker's inference. Proves the system\n   works, not just that you annotated correctly.\n2. **Annotation fallback** — `x: Tensor[[B, C, H, W]] = unrefined_op(...)`.\n   Use when the op returns unrefined but you know the shape. Document WHY.\n3. **`type: ignore`** — the checker produces a WRONG type (algebraic gap\n   or conditional equality). Last resort. Always include a comment\n   explaining the specific gap.\n4. **Bare `Tensor`** — shape genuinely unknowable. Data-dependent token\n   counts, conditional accumulation. Document the specific reason.\n\nType the forward signature:\n- Class params for fixed dims (set at construction), method params for\n  per-call dims (batch size, sequence length, spatial dims).\n- Put parameters whose type vars appear in bare (directly bindable)\n  positions BEFORE parameters where they appear inside arithmetic\n  expressions. The checker needs to bind the bare params first.\n- **Don't hide known class dims inside variadic params.** If the module\n  has a class-level Int `D`, spell the trailing dim out with the variadic\n  batch idiom: `Tensor[[*Elements[Bs], D]]` (with `Bs: IntTuple`), not a\n  whole-shape `Tensor[S]` that swallows `D`. See `examples\u002Ftacotron2.py`.\n\nReplace every `reveal_type` with `assert_type` using the recorded types:\n- Shaped `reveal_type` → `assert_type(x, Tensor[...])` with that shape.\n- Bare `reveal_type` → `assert_type(x, Tensor)` to document the tracking\n  gap, plus a comment noting the root cause (e.g., `# Sequential(*list)`).\n\n**Every local variable in every forward method gets an `assert_type`.**\nNo exceptions — even inside typed-interface modules. Typed interface means\nthe *boundary* is typed — it does NOT mean internals are exempt from\n`assert_type`. If you think a shape expression is \"too complex to write,\"\nyou are guessing — look at what `reveal_type` showed you. The checker\nsimplifies aggressively.\n\nRun the checker. Fix any `assert_type` failures.\n\n**VERIFY before leaving Step 5.** Paste this in your response:\n\n```\n# assert_type count for ClassName.forward:\n# Locals: var1, var2, var3 (N total)\n# assert_type calls: N\n# Match: yes\n```\n\nIf the counts don't match, you missed some. Go back and add them.\n\n**Step 4 receipt check.** Every bare `assert_type(x, Tensor)` and\nevery annotation fallback (`x: Tensor[[B, C]] = untracked_op(...)`)\nmust cite the Step 4 receipt that justifies it. If no receipt exists,\ngo back to Step 4 — the restructuring attempt was skipped.\n\n```\n# Bare\u002Ffallback assert_types and their Step 4 receipts:\n# - var2 (bare): receipt MLP.var2 — Sequential(*list), not restructurable\n# - var3 (fallback): receipt MLP.var3 — stub returns unrefined, shape known from context\n# - var5 (bare): receipt MLP.var5 — input is bare (upstream contagion)\n```\n\n**Smoke tests at the bottom of the file** must use `assert_type` on\nthe typed output, not `assert out.shape == (...)`. Runtime shape\nasserts don't exercise pyrefly — they only prove the model runs.\nExample:\n\n```python\nmodel = MyModel(num_classes=10)\nx = torch.randn(2, 3, 32, 32)  # inferred as Tensor[[2, 3, 32, 32]]\nout = model(x)\nassert_type(out, Tensor[[2, 10]])  # not: assert out.shape == (2, 10)\n```\n\n## Step 6: Post-module checklist\n\nCopy this template into your response and fill **every line** before\nproceeding to the next module.\n\n```\n### Post-module: \u003CClassName>\n- type: ignore count: ___\n  For each: [line] [category: A1 \u002F conditional \u002F stub-gap] [fix attempted]\n- Step 4 receipts: [list receipt IDs, or \"none — all locals shaped\"]\n- int params: [list each int param and why it's not Int, or \"none\"]\n- int() casts: [list each, or \"none\"]\n- Sequential(*list): [list each instance and what you did, or \"none\"]\n- bare Tensor in sigs: [list each with reason, or \"none\"]\n- assert_type: ___ checkpoints covering ___ locals in ___ forward methods\n- missing stubs: [list each, or \"none\"]\n```\n\nDo not proceed to the next module with unfilled lines.\n\n# Verification (draft review)\n\nEverything above produced a DRAFT. This phase reviews it.\n\n## Run verify_port.sh\n\nRun `verify_port.sh` (in this skill dir) on your port file:\n\n```bash\ntensor-shapes\u002Fskills\u002Fadd-shape-types-to-torch-model\u002Fverify_port.sh \u003Cpath\u002Fto\u002Fyour\u002Fport.py>\n```\n\n**Paste the FULL output** in your response. Do not summarize or\nparaphrase — the raw output is the artifact.\n\n## Run the actual Pyrefly check\n\n`verify_port.sh` is a heuristic quality gate; it does not type check the port.\nYou must also run Pyrefly itself against your port file. There is no\n`--tensor-shapes` flag — shape tracking is on whenever the shape stubs and\n`shape_extensions` are on the search path. The single-file check mirrors\n`tensor-shapes\u002Fpyrefly-torch-stubs\u002Frun_pyrefly.py`:\n\n```bash\npyrefly check --config \u002Fdev\u002Fnull --python-version 3.13 \\\n    --search-path \u003Croot containing torch-stubs> \\\n    --search-path \u003Croot containing shape_extensions> \\\n    path\u002Fto\u002Fyour\u002Fport.py\n```\n\nThe two search roots are separate: `tensor-shapes\u002Fpyrefly-torch-stubs` (the\n`torch-stubs` package) and `tensor-shapes\u002Fpyrefly-shape-extensions` (the\n`shape_extensions` package). In a Buck checkout you can instead pass the combined\nfilegroup `fbcode\u002F\u002Fpyrefly\u002Ftensor-shapes:torch-stubs-search-path` as a\n`--search-path`. If a skill invoked this one, it may supply its own\nbuild-and-check command; use that instead. `pyrefly dump-config` reports the\nresolved search path when the stubs are already installed in your environment.\n\n**Python version:** the PEP 695\u002F696 generics syntax (`class Net[D: IntVar]`,\ntype-param defaults) requires `--python-version 3.12` or later; the corpus runs\n`3.13`.\n\nTo type-check the whole corpus (or a stack of edits) at once:\n\n```bash\npython3 tensor-shapes\u002Frun_all_shape_tests.py --mode cargo|buck [--include-runtime-tests]\n```\n\nPaste the Pyrefly output. The result must be `0 errors`; `reveal_type` info is\nacceptable only while probing and must not remain in the finished port.\n\n## Investigate each warning\n\nFor EACH warning in the verify_port.sh output, write one of:\n- **Fixed**: what you changed and why.\n- **Accepted**: why this warning is not actionable (cite the specific\n  category — A1 algebraic, conditional equality, stub gap not worth\n  fixing, etc.).\n\nDo not write \"all warnings audited\" — list them individually.\n\n## Audit bare assert_types\n\nThe port's quality metric is: what fraction of `assert_type` calls verify\na shaped type vs. document a bare `Tensor` gap? Every bare\n`assert_type(x, Tensor)` is a tracking gap. Minimizing these is the goal.\n\nFor each `assert_type(x, Tensor)` in the port (bare, no shape params):\n1. It MUST have a comment explaining the root cause (e.g.,\n   `# Sequential(*list)`, `# input is bare`).\n2. The root cause MUST have a typed interface receipt from Step 4\n   (or trace to one — e.g., \"input is bare\" because the caller's\n   Sequential(*list) was documented in the parent module's receipt).\n\nIf any bare `assert_type` lacks a comment or receipt trail, go back\nand either fix the tracking gap or document it properly.\n\n**Paste the bare audit in your response:**\n\n```\n## Bare assert_type audit\nTotal assert_type in forward bodies: ___\nShaped (assert_type(x, Tensor[...])): ___\nBare (assert_type(x, Tensor)): ___\nBare fraction: ___\n\nEach bare:\n- line N: var — root cause (receipt: \u003Cmodule>.Step4)\n- line M: var — root cause (receipt: \u003Cmodule>.Step4)\n```\n\n## Compare against known patterns\n\n**Read `style_guide.md` NOW — not earlier.** It is comparison material\nfor your draft, not preparation material. Reading it during pre-flight\nbiases you toward patterns you haven't empirically verified.\n\nFor each module in your port, find the closest matching pattern in the\nstyle guide. **Paste a comparison:**\n\n```\n## Style guide comparison\n| Module | My approach | Closest style guide pattern | Could I improve? |\n|--------|------------|---------------------------|-----------------|\n| ... | ... | ... | yes\u002Fno — reason |\n```\n\nIf any row says \"yes\", go back and try the improvement before proceeding.\nIf it doesn't work, document why in the row.\n\n## Re-run verify_port.sh\n\nIf you made any changes during this phase, re-run the script and paste\nthe new output. If no changes were made, write \"No changes — output\nunchanged.\"\n\n**Re-check callers.** If you changed a module's forward signature or\nreturn type during this phase, re-run `reveal_type` in every module\nthat calls it and update their `assert_type` expectations. A fix to\nmodule X can change the inferred types in module Y's forward body.\n\n## Completion report\n\nBefore reporting the port as done, copy and fill this template in your\nresponse. **Do not report completion with unfilled blanks.**\n\n```\n## Port complete: \u003Cmodel name>\nGate 1 ops audited: ___. Stubs added\u002Ffixed: ___.\nGate 2 inventory items: ___. All checked off: yes\u002Fno.\nModules ported (dependency order): ___\nStep 6 checklists filled for each: yes\u002Fno\ntype: ignore total: ___\n  ___ A1 algebraic, ___ conditional equality, ___ stub gap, ___ other\nassert_type total: ___ (___ shaped, ___ bare)\nBare fraction: ___%\nEach bare assert_type has comment + receipt trail: yes\u002Fno\nsmoke tests: ___ — all use `assert_type` on typed output (not `.shape ==`): yes\u002Fno\n\nVerification phase:\n- verify_port.sh warnings: ___\n  Fixed: ___. Accepted: ___ (each justified above).\n- Pyrefly check: 0 errors: yes\u002Fno\n- Style guide comparison rows: ___\n  Improvements attempted: ___. Improvements that worked: ___.\n- verify_port.sh re-run (if changes made): 0 actionable: yes\u002Fno\n\nGaps & proposed improvements (for the user):\n- Ops that stayed untracked, and why: ___ (or \"none\")\n- Stub-signature improvements that would recover shapes (if stubs weren't\n  changed): ___ (or \"none\")\n- Wrong computed shapes found (needing a shape-DSL change): ___ (or \"none\")\n- Suggest filing an upstream issue for: ___ (or \"none\")\n```\n\nThe \"Gaps & proposed improvements\" block is the user-facing payload of the\nlighter deliverable — when you didn't paste the full tables, this is where the\nshortcomings of the port surface. Fill it from the `GAP`s you recorded in Gate 1\nand the Step 4 receipts.\n\n# Import convention\n\nThe `shape_extensions` package bridges pyrefly's type system and Python runtime.\nImporting it patches `torch.Tensor`, `nn.Conv2d`, and other torch classes to\naccept subscript syntax (e.g., `Tensor[[B, C, H, W]]`) at runtime without\ncrashing. It also provides `IntVar` with arithmetic support (`N + 1`, `N \u002F\u002F 2`\nreturn `self` instead of `TypeError`) and `Int` for binding runtime ints to\ntype-level symbols.\n\n`shape_extensions` is installed alongside the shape-aware torch stubs (wherever\nthose live in your environment — `pyrefly dump-config` reports the location). In an\nfbsource Buck checkout specifically, the runtime package is\n`fbcode\u002F\u002Fpyrefly\u002Ftensor-shapes\u002Fpyrefly-shape-extensions:shape_extensions`, the importable stub package is\n`fbcode\u002F\u002Fpyrefly\u002Ftensor-shapes\u002Fpyrefly-torch-stubs:torch-stubs`, and the\nfilegroup to pass as a Pyrefly `--search-path` is\n`fbcode\u002F\u002Fpyrefly\u002Ftensor-shapes:torch-stubs-search-path`.\n\nPick an import mode based on whether the port file will be **executed**, not\njust type-checked:\n\n*Static-check-only (common case — you only run the checker on the file):* guard\nthe shape imports. The file is never executed, so the annotations never evaluate\nand the guarded names need not resolve at runtime.\n\n```python\nfrom typing import assert_type, TYPE_CHECKING\n\nimport torch\nimport torch.nn as nn\n\nif TYPE_CHECKING:\n    from torch import Tensor\n    from shape_extensions import Elements, Int, IntTuple, IntVar\n```\n\n*Runnable (the file is imported\u002Fexecuted):* a guarded import alone will crash,\nbecause annotations — and PEP 695 type-param bounds — still evaluate at runtime.\nEither:\n- add `from __future__ import annotations` to postpone annotation evaluation,\n  and import the symbols that appear in *runtime-evaluated* positions\n  (`Elements`, plus the bounds `IntVar`\u002F`IntTuple` used in `[Bs: IntTuple]`) at\n  module top — see `examples\u002Fruntime\u002Fnanogpt_future_annotations_runnable.py`; or\n- import all shape symbols at module top with no guard — see\n  `examples\u002Fruntime\u002Fgptfast_sym_int_var_runnable.py`.\n\n`Int` binds runtime ints; `IntVar` is the bound for scalar dim params\n(`[D: IntVar]`); `IntTuple` is the bound for variadic\u002Fwhole-shape params\n(`[Bs: IntTuple]`); `Elements` unpacks a variadic batch\n(`Tensor[[*Elements[Bs], D]]`). Import only the ones a given file uses.\n\n**Runtime-compatible annotations:** if you need annotations to evaluate at\nruntime (e.g., for runtime shape validation), import `shape_extensions` directly\n(not under `TYPE_CHECKING`). Use old-style `shape_extensions.IntVar` instead of\nPEP 695 syntax, since `class Foo[T]` doesn't support arithmetic on `T` at\nruntime. Alternatively, `from __future__ import annotations` defers evaluation\nso annotations never execute, but then `assert_type` becomes a no-op at\nruntime.\n",{"data":54,"body":55},{"name":4,"description":6},{"type":56,"children":57},"root",[58,66,94,107,132,139,144,246,258,264,274,279,286,352,370,376,458,522,532,544,580,599,626,632,637,692,709,714,740,746,751,761,766,778,784,794,811,817,822,875,894,902,1514,1520,1539,1564,1618,1626,1749,1765,1820,1832,1871,1876,1889,1942,1947,2040,2076,2093,2105,2111,2145,2157,2167,2176,2181,2191,2203,2230,2236,2248,2260,2301,2339,2401,2455,2482,2501,2526,2552,2584,2602,2614,2624,2633,2638,2657,2680,2786,2799,2888,2940,2970,2976,2986,3047,3052,3120,3138,3185,3222,3234,3244,3253,3258,3283,3292,3317,3356,3362,3374,3383,3388,3394,3399,3405,3418,3459,3469,3475,3507,3636,3694,3727,3732,3777,3797,3803,3808,3831,3836,3842,3868,3880,3906,3918,3926,3935,3941,3957,3967,3976,3981,3987,3992,4016,4022,4032,4041,4053,4059,4137,4183,4195,4205,4274,4284,4355,4407,4470],{"type":59,"tag":60,"props":61,"children":62},"element","p",{},[63],{"type":64,"value":65},"text","You are porting a PyTorch model to use pyrefly's tensor shape type system.",{"type":59,"tag":60,"props":67,"children":68},{},[69,75,77,84,86,92],{"type":59,"tag":70,"props":71,"children":72},"strong",{},[73],{"type":64,"value":74},"The methodology below is mandatory; how much you write down depends on the\njob.",{"type":64,"value":76}," Each step has an artifact — an audit table, a per-local ",{"type":59,"tag":78,"props":79,"children":81},"code",{"className":80},[],[82],{"type":64,"value":83},"reveal_type",{"type":64,"value":85},"\ndump, a typed-interface receipt, an ",{"type":59,"tag":78,"props":87,"children":89},{"className":88},[],[90],{"type":64,"value":91},"assert_type",{"type":64,"value":93}," count. Working through them in\norder is not optional: the next step's input is the previous step's output, and\nskipping a step means substituting reasoning for testing, which is the primary\nfailure mode.",{"type":59,"tag":60,"props":95,"children":96},{},[97,99,105],{"type":64,"value":98},"What varies is the ",{"type":59,"tag":100,"props":101,"children":102},"em",{},[103],{"type":64,"value":104},"deliverable",{"type":64,"value":106},":",{"type":59,"tag":108,"props":109,"children":110},"ul",{},[111,122],{"type":59,"tag":112,"props":113,"children":114},"li",{},[115,120],{"type":59,"tag":70,"props":116,"children":117},{},[118],{"type":64,"value":119},"Annotating someone's own model",{"type":64,"value":121}," (the common case): do every step as internal\nreasoning, but what you hand back is the annotated model plus a short report of\nwhat couldn't be tracked. You don't need to paste every table — the \"paste this\"\ninstructions below are for the contribution case.",{"type":59,"tag":112,"props":123,"children":124},{},[125,130],{"type":59,"tag":70,"props":126,"children":127},{},[128],{"type":64,"value":129},"Contributing a reference example",{"type":64,"value":131}," (e.g. into a maintained example corpus):\nthe tables, receipts, and counts ARE part of the deliverable — paste them in\nfull, because others read these ports to learn the patterns. A skill that\ninvokes this one for corpus work will say so; absent that, assume the lighter\ndeliverable.",{"type":59,"tag":133,"props":134,"children":136},"h1",{"id":135},"before-you-start-two-questions",[137],{"type":64,"value":138},"Before you start: two questions",{"type":59,"tag":60,"props":140,"children":141},{},[142],{"type":64,"value":143},"Resolve these with the user before Gate 0. In the common case these are the only\ntwo times you interrupt them:",{"type":59,"tag":145,"props":146,"children":147},"ol",{},[148,206],{"type":59,"tag":112,"props":149,"children":150},{},[151,156,158,164,166,172,174,180,182,188,190,196,198,204],{"type":59,"tag":70,"props":152,"children":153},{},[154],{"type":64,"value":155},"Confirm how you'll check, and where the stubs are.",{"type":64,"value":157}," State it operationally —\ne.g. \"I'll type-check with ",{"type":59,"tag":78,"props":159,"children":161},{"className":160},[],[162],{"type":64,"value":163},"\u003Ccommand>",{"type":64,"value":165}," against the shape stubs at ",{"type":59,"tag":78,"props":167,"children":169},{"className":168},[],[170],{"type":64,"value":171},"\u003Cpath>",{"type":64,"value":173},",\ncorrect?\" — and let the user confirm or correct. Don't make them reason about\ninternal concepts; just confirm a command and a location. Default the command\nto ",{"type":59,"tag":78,"props":175,"children":177},{"className":176},[],[178],{"type":64,"value":179},"pyrefly check",{"type":64,"value":181}," (assume ",{"type":59,"tag":78,"props":183,"children":185},{"className":184},[],[186],{"type":64,"value":187},"pyrefly",{"type":64,"value":189}," is on ",{"type":59,"tag":78,"props":191,"children":193},{"className":192},[],[194],{"type":64,"value":195},"PATH",{"type":64,"value":197},", however it was installed) and\ndiscover where the stubs live from ",{"type":59,"tag":78,"props":199,"children":201},{"className":200},[],[202],{"type":64,"value":203},"pyrefly dump-config",{"type":64,"value":205},", which prints the\nresolved search path. If a skill invoked this one, it may supply both instead\n(for example, an in-repo build-and-check command).",{"type":59,"tag":112,"props":207,"children":208},{},[209,214,216],{"type":59,"tag":70,"props":210,"children":211},{},[212],{"type":64,"value":213},"Ask whether they're open to changing the stubs.",{"type":64,"value":215}," Adding or refining a stub\nsignature can recover shapes an op would otherwise lose.\n",{"type":59,"tag":108,"props":217,"children":218},{},[219,229],{"type":59,"tag":112,"props":220,"children":221},{},[222,227],{"type":59,"tag":70,"props":223,"children":224},{},[225],{"type":64,"value":226},"No",{"type":64,"value":228}," (or unsure): don't touch the stubs. Port the model as well as the\nexisting stubs allow, collect what couldn't be tracked, and report it at the\nend (see Completion report), suggesting an upstream issue for the gaps worth\nclosing. This path is fully supported — a less-complete port is the expected\noutcome here, not a failure.",{"type":59,"tag":112,"props":230,"children":231},{},[232,237,239,244],{"type":59,"tag":70,"props":233,"children":234},{},[235],{"type":64,"value":236},"Yes",{"type":64,"value":238},": you have standing permission to make straightforward stub-signature\nimprovements as you go. Don't re-ask per op. Still port first and confirm the\ngap with ",{"type":59,"tag":78,"props":240,"children":242},{"className":241},[],[243],{"type":64,"value":83},{"type":64,"value":245}," before editing a stub.",{"type":59,"tag":60,"props":247,"children":248},{},[249,251,256],{"type":64,"value":250},"Don't ask about deeper changes (teaching Pyrefly new shape ",{"type":59,"tag":100,"props":252,"children":253},{},[254],{"type":64,"value":255},"logic",{"type":64,"value":257},") up front —\nthat comes up only reactively, and rarely (see \"When an op's shape is wrong\").",{"type":59,"tag":133,"props":259,"children":261},{"id":260},"pre-flight",[262],{"type":64,"value":263},"Pre-flight",{"type":59,"tag":60,"props":265,"children":266},{},[267,272],{"type":59,"tag":70,"props":268,"children":269},{},[270],{"type":64,"value":271},"Create tasks",{"type":64,"value":273}," for each gate and the module loop\u002Fverification phases\nthat follow. Update them as you complete each stage — this gives\nvisibility during long-running ports.",{"type":59,"tag":60,"props":275,"children":276},{},[277],{"type":64,"value":278},"Complete these gates before writing any code.",{"type":59,"tag":280,"props":281,"children":283},"h2",{"id":282},"gate-0-understand-the-system",[284],{"type":64,"value":285},"Gate 0: Understand the system",{"type":59,"tag":60,"props":287,"children":288},{},[289,291,297,299,305,307,313,315,321,322,328,329,335,336,342,344,350],{"type":64,"value":290},"Read ",{"type":59,"tag":78,"props":292,"children":294},{"className":293},[],[295],{"type":64,"value":296},"shape_tracking_capabilities.md",{"type":64,"value":298}," (this skill dir). It explains the\nthree shape-tracking mechanisms (shape-aware stubs, DSL functions, special\nhandlers) and how to check each one, plus the current ",{"type":59,"tag":78,"props":300,"children":302},{"className":301},[],[303],{"type":64,"value":304},"shape_extensions",{"type":64,"value":306}," API\nsurface (",{"type":59,"tag":78,"props":308,"children":310},{"className":309},[],[311],{"type":64,"value":312},"Int",{"type":64,"value":314}," \u002F ",{"type":59,"tag":78,"props":316,"children":318},{"className":317},[],[319],{"type":64,"value":320},"IntVar",{"type":64,"value":314},{"type":59,"tag":78,"props":323,"children":325},{"className":324},[],[326],{"type":64,"value":327},"IntTuple",{"type":64,"value":314},{"type":59,"tag":78,"props":330,"children":332},{"className":331},[],[333],{"type":64,"value":334},"Elements",{"type":64,"value":314},{"type":59,"tag":78,"props":337,"children":339},{"className":338},[],[340],{"type":64,"value":341},"assert_shape",{"type":64,"value":343}," \u002F runtime\ncompat) and the double-bracket ",{"type":59,"tag":78,"props":345,"children":347},{"className":346},[],[348],{"type":64,"value":349},"Tensor[[...]]",{"type":64,"value":351}," convention. You need this context\nto make the Gate 1 audit meaningful — knowing whether an op exists in a stub is\nnot the same as knowing whether its shapes are tracked.",{"type":59,"tag":60,"props":353,"children":354},{},[355,368],{"type":59,"tag":70,"props":356,"children":357},{},[358,360,366],{"type":64,"value":359},"Do NOT read ",{"type":59,"tag":78,"props":361,"children":363},{"className":362},[],[364],{"type":64,"value":365},"style_guide.md",{"type":64,"value":367}," yet.",{"type":64,"value":369}," It is comparison material for the\nverification phase. Reading it now biases you toward known patterns\nbefore you have empirically probed this model's shapes.",{"type":59,"tag":280,"props":371,"children":373},{"id":372},"gate-1-audit-ops",[374],{"type":64,"value":375},"Gate 1: Audit ops",{"type":59,"tag":60,"props":377,"children":378},{},[379,381,387,389,395,397,403,405,411,413,418,420,426,428,434,436,442,444,449,451,456],{"type":64,"value":380},"List every ",{"type":59,"tag":78,"props":382,"children":384},{"className":383},[],[385],{"type":64,"value":386},"nn.Module",{"type":64,"value":388}," subclass and ",{"type":59,"tag":78,"props":390,"children":392},{"className":391},[],[393],{"type":64,"value":394},"torch",{"type":64,"value":396},"\u002F",{"type":59,"tag":78,"props":398,"children":400},{"className":399},[],[401],{"type":64,"value":402},"F.",{"type":64,"value":404}," function called in the\nmodel. Check each against the shape-aware torch stubs (the ",{"type":59,"tag":78,"props":406,"children":408},{"className":407},[],[409],{"type":64,"value":410},".pyi",{"type":64,"value":412}," files under the\nstub root you confirmed up front — ",{"type":59,"tag":78,"props":414,"children":416},{"className":415},[],[417],{"type":64,"value":203},{"type":64,"value":419}," reports it) and any shape\nDSL declarations in those stubs. The stubs attach DSL shape functions with\n",{"type":59,"tag":78,"props":421,"children":423},{"className":422},[],[424],{"type":64,"value":425},"@uses_shape_dsl(ir_fn)",{"type":64,"value":427},", and the IR functions live in ",{"type":59,"tag":78,"props":429,"children":431},{"className":430},[],[432],{"type":64,"value":433},"_shapes.pyi",{"type":64,"value":435}," next to the\nstubs, imported from stub files as ",{"type":59,"tag":78,"props":437,"children":439},{"className":438},[],[440],{"type":64,"value":441},"torch._shapes",{"type":64,"value":443}," because the stub package\nprovides the ",{"type":59,"tag":78,"props":445,"children":447},{"className":446},[],[448],{"type":64,"value":394},{"type":64,"value":450}," package for type checking. This is a ",{"type":59,"tag":70,"props":452,"children":453},{},[454],{"type":64,"value":455},"diagnostic",{"type":64,"value":457}," pass — you are recording\nwhich ops are tracked and which aren't, not fixing anything. A gap here never\nblocks the port. This step should take minutes — you are scanning the stub file\nfor the op and, only when a decorator points there, the corresponding IR\nfunction.",{"type":59,"tag":60,"props":459,"children":460},{},[461,466,468,473,475,481,482,488,490,496,498,504,506,512,514,520],{"type":59,"tag":70,"props":462,"children":463},{},[464],{"type":64,"value":465},"Do NOT delegate this audit to code search agents or use web search for this\nstep.",{"type":64,"value":467}," The torch-stubs package and its ",{"type":59,"tag":78,"props":469,"children":471},{"className":470},[],[472],{"type":64,"value":433},{"type":64,"value":474}," DSL\nfile are exhaustive for torch shape support. For each op in your list, check\nwhether it appears in the relevant stub file and whether it has a precise\ngeneric signature, ",{"type":59,"tag":78,"props":476,"children":478},{"className":477},[],[479],{"type":64,"value":480},"Self",{"type":64,"value":396},{"type":59,"tag":78,"props":483,"children":485},{"className":484},[],[486],{"type":64,"value":487},"Tensor[S]",{"type":64,"value":489}," (whole-shape ",{"type":59,"tag":78,"props":491,"children":493},{"className":492},[],[494],{"type":64,"value":495},"S: IntTuple",{"type":64,"value":497},") return, or ",{"type":59,"tag":78,"props":499,"children":501},{"className":500},[],[502],{"type":64,"value":503},"@uses_shape_dsl(...)",{"type":64,"value":505},"\ndecorator that refines a bare declared return. Use targeted file reads or\nrepo-approved search scoped to known files\u002Fdirectories, not broad recursive\nshell search. You need to confirm presence and spot missing attributes\n(e.g., ",{"type":59,"tag":78,"props":507,"children":509},{"className":508},[],[510],{"type":64,"value":511},"bias",{"type":64,"value":513}," on ",{"type":59,"tag":78,"props":515,"children":517},{"className":516},[],[518],{"type":64,"value":519},"Conv2d",{"type":64,"value":521},"), not memorize every signature.",{"type":59,"tag":60,"props":523,"children":524},{},[525,530],{"type":59,"tag":70,"props":526,"children":527},{},[528],{"type":64,"value":529},"Paste your audit table",{"type":64,"value":531}," in your response before proceeding to Gate 2:",{"type":59,"tag":533,"props":534,"children":538},"pre",{"className":535,"code":537,"language":64},[536],"language-text","## Gate 1: Ops audit\n| Op | Stub location | Shape DSL decorator \u002F IR fn (or \"no decorator\") | Status |\n|----|---------------|------------------------------|--------|\n| nn.Conv2d | tensor-shapes\u002Fpyrefly-torch-stubs\u002Ftorch-stubs\u002Fnn\u002F__init__.pyi — generic [InC,OutC,K,S,P,D] | no decorator (stub generic) | tracked-stub |\n| F.adaptive_avg_pool2d | tensor-shapes\u002Fpyrefly-torch-stubs\u002Ftorch-stubs\u002Fnn\u002Ffunctional.pyi — bare declared return | `@uses_shape_dsl(adaptive_pool_ir)`, defined in `_shapes.pyi` | tracked-DSL |\n| ...\n",[539],{"type":59,"tag":78,"props":540,"children":542},{"__ignoreMap":541},"",[543],{"type":64,"value":537},{"type":59,"tag":60,"props":545,"children":546},{},[547,549,555,557,563,564,570,572,578],{"type":64,"value":548},"Status is one of ",{"type":59,"tag":78,"props":550,"children":552},{"className":551},[],[553],{"type":64,"value":554},"tracked-stub",{"type":64,"value":556},", ",{"type":59,"tag":78,"props":558,"children":560},{"className":559},[],[561],{"type":64,"value":562},"tracked-DSL",{"type":64,"value":556},{"type":59,"tag":78,"props":565,"children":567},{"className":566},[],[568],{"type":64,"value":569},"tracked-handler",{"type":64,"value":571}," (a special\nhandler tracks it), or ",{"type":59,"tag":78,"props":573,"children":575},{"className":574},[],[576],{"type":64,"value":577},"GAP",{"type":64,"value":579}," (no shape support found).",{"type":59,"tag":60,"props":581,"children":582},{},[583,585,590,592,597],{"type":64,"value":584},"Filling the \"Shape DSL decorator \u002F IR fn\" column requires checking whether\nthe stub declaration has a ",{"type":59,"tag":78,"props":586,"children":588},{"className":587},[],[589],{"type":64,"value":503},{"type":64,"value":591}," decorator. If it does,\nconfirm the named IR function exists in ",{"type":59,"tag":78,"props":593,"children":595},{"className":594},[],[596],{"type":64,"value":433},{"type":64,"value":598}," next to the stubs.\nWrite \"no decorator\" only after confirming the stub declaration has no\ndecorator — do not leave this column blank or write \"check DSL\".",{"type":59,"tag":60,"props":600,"children":601},{},[602,604,609,611,617,619,624],{"type":64,"value":603},"A ",{"type":59,"tag":78,"props":605,"children":607},{"className":606},[],[608],{"type":64,"value":577},{"type":64,"value":610}," is information, not a blocker — note it and move on. You decide what to do\nabout gaps later: most degrade gracefully to a bare ",{"type":59,"tag":78,"props":612,"children":614},{"className":613},[],[615],{"type":64,"value":616},"Tensor",{"type":64,"value":618},", and only if the user\nopted into stub changes is a ",{"type":59,"tag":78,"props":620,"children":622},{"className":621},[],[623],{"type":64,"value":577},{"type":64,"value":625}," worth a stub fix.",{"type":59,"tag":280,"props":627,"children":629},{"id":628},"gate-2-inventory-the-original",[630],{"type":64,"value":631},"Gate 2: Inventory the original",{"type":59,"tag":60,"props":633,"children":634},{},[635],{"type":64,"value":636},"Write the inventory as a comment block at the top of the port file, using\nthis exact format:",{"type":59,"tag":533,"props":638,"children":641},{"className":639,"code":640,"language":25,"meta":541,"style":541},"language-python shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","# ## Inventory\n# - [ ] ClassName.__init__ — Int: param1, param2; int: param3\n# - [ ] ClassName.forward\n# - [ ] function_name — utility, no tensors\n# ...\n",[642],{"type":59,"tag":78,"props":643,"children":644},{"__ignoreMap":541},[645,656,665,674,683],{"type":59,"tag":646,"props":647,"children":650},"span",{"class":648,"line":649},"line",1,[651],{"type":59,"tag":646,"props":652,"children":653},{},[654],{"type":64,"value":655},"# ## Inventory\n",{"type":59,"tag":646,"props":657,"children":659},{"class":648,"line":658},2,[660],{"type":59,"tag":646,"props":661,"children":662},{},[663],{"type":64,"value":664},"# - [ ] ClassName.__init__ — Int: param1, param2; int: param3\n",{"type":59,"tag":646,"props":666,"children":668},{"class":648,"line":667},3,[669],{"type":59,"tag":646,"props":670,"children":671},{},[672],{"type":64,"value":673},"# - [ ] ClassName.forward\n",{"type":59,"tag":646,"props":675,"children":677},{"class":648,"line":676},4,[678],{"type":59,"tag":646,"props":679,"children":680},{},[681],{"type":64,"value":682},"# - [ ] function_name — utility, no tensors\n",{"type":59,"tag":646,"props":684,"children":686},{"class":648,"line":685},5,[687],{"type":59,"tag":646,"props":688,"children":689},{},[690],{"type":64,"value":691},"# ...\n",{"type":59,"tag":60,"props":693,"children":694},{},[695,700,702,707],{"type":59,"tag":70,"props":696,"children":697},{},[698],{"type":64,"value":699},"Every class, function, and method in the original file must appear, and\nevery item must be ported.",{"type":64,"value":701}," Do not skip or exclude anything. If a class\ndepends on a library without shape-aware stubs, port it anyway — its tensors\nfall back to bare ",{"type":59,"tag":78,"props":703,"children":705},{"className":704},[],[706],{"type":64,"value":616},{"type":64,"value":708},", which is acceptable; record the gap for the report.\nOnly if the user opted into stub changes, and a minimal stub for the specific\nops used would recover real shapes, is adding one worthwhile.",{"type":59,"tag":60,"props":710,"children":711},{},[712],{"type":64,"value":713},"For each class, list constructor parameters and whether each is Int or\nint — this feeds Step 1 of the module loop.",{"type":59,"tag":60,"props":715,"children":716},{},[717,722,724,730,732,738],{"type":59,"tag":70,"props":718,"children":719},{},[720],{"type":64,"value":721},"Check off items as you port them",{"type":64,"value":723}," (",{"type":59,"tag":78,"props":725,"children":727},{"className":726},[],[728],{"type":64,"value":729},"[ ]",{"type":64,"value":731}," → ",{"type":59,"tag":78,"props":733,"children":735},{"className":734},[],[736],{"type":64,"value":737},"[x]",{"type":64,"value":739},"). Do not proceed to\nverification with unchecked items.",{"type":59,"tag":133,"props":741,"children":743},{"id":742},"transition-to-module-loop",[744],{"type":64,"value":745},"Transition to module loop",{"type":59,"tag":60,"props":747,"children":748},{},[749],{"type":64,"value":750},"You have completed pre-flight. You have NOT written any model code yet.",{"type":59,"tag":60,"props":752,"children":753},{},[754,759],{"type":59,"tag":70,"props":755,"children":756},{},[757],{"type":64,"value":758},"Your analysis so far is a hypothesis.",{"type":64,"value":760}," The module loop tests it\nempirically. If you catch yourself planning multiple modules' forwards\nin your head, STOP — you are substituting reasoning for testing, and\nreasoning is less reliable.",{"type":59,"tag":60,"props":762,"children":763},{},[764],{"type":64,"value":765},"Write the file with imports, the inventory comment, and utility functions\n(no tensor shapes). Then start Step 1 for the FIRST module only.",{"type":59,"tag":60,"props":767,"children":768},{},[769,770,776],{"type":64,"value":290},{"type":59,"tag":78,"props":771,"children":773},{"className":772},[],[774],{"type":64,"value":775},"porting_principles.md",{"type":64,"value":777}," (this skill dir) for the mindset: why we port,\npriority order, and stub philosophy.",{"type":59,"tag":133,"props":779,"children":781},{"id":780},"module-loop",[782],{"type":64,"value":783},"Module loop",{"type":59,"tag":60,"props":785,"children":786},{},[787,792],{"type":59,"tag":70,"props":788,"children":789},{},[790],{"type":64,"value":791},"Repeat the following for each module in dependency order.",{"type":64,"value":793}," Each module's\ntyping may inform the next — e.g., discovering that a submodule tracks\nshapes internally changes how the parent handles its loop.",{"type":59,"tag":60,"props":795,"children":796},{},[797,802,804,809],{"type":59,"tag":70,"props":798,"children":799},{},[800],{"type":64,"value":801},"ONE MODULE AT A TIME.",{"type":64,"value":803}," Complete Steps 1–6 for module A, paste the\nStep 6 checklist, THEN start Step 1 for module B. If you find yourself\ntyping two modules' constructors before running the checker, you have\nalready entered the primary failure mode: writing the entire file and\nvalidating at the end leads to over-use of typed interfaces and under-use\nof ",{"type":59,"tag":78,"props":805,"children":807},{"className":806},[],[808],{"type":64,"value":91},{"type":64,"value":810},".",{"type":59,"tag":280,"props":812,"children":814},{"id":813},"step-1-inventory-parameters",[815],{"type":64,"value":816},"Step 1: Inventory parameters",{"type":59,"tag":60,"props":818,"children":819},{},[820],{"type":64,"value":821},"List every constructor parameter. For each, decide:",{"type":59,"tag":108,"props":823,"children":824},{},[825,850],{"type":59,"tag":112,"props":826,"children":827},{},[828,832,834,840,842,848],{"type":59,"tag":70,"props":829,"children":830},{},[831],{"type":64,"value":312},{"type":64,"value":833},": the value determines a tensor dimension (flows to ",{"type":59,"tag":78,"props":835,"children":837},{"className":836},[],[838],{"type":64,"value":839},"nn.Linear",{"type":64,"value":841},",\n",{"type":59,"tag":78,"props":843,"children":845},{"className":844},[],[846],{"type":64,"value":847},"nn.Conv2d",{"type":64,"value":849},", tensor creation, or any typed function that uses the value\nas a shape dimension).",{"type":59,"tag":112,"props":851,"children":852},{},[853,858,860,866,867,873],{"type":59,"tag":70,"props":854,"children":855},{},[856],{"type":64,"value":857},"int",{"type":64,"value":859},": iteration count (",{"type":59,"tag":78,"props":861,"children":863},{"className":862},[],[864],{"type":64,"value":865},"n_layers",{"type":64,"value":556},{"type":59,"tag":78,"props":868,"children":870},{"className":869},[],[871],{"type":64,"value":872},"n_res_block",{"type":64,"value":874},") or boolean-like flag.",{"type":59,"tag":60,"props":876,"children":877},{},[878,880,885,887,892],{"type":64,"value":879},"If in doubt, make it ",{"type":59,"tag":78,"props":881,"children":883},{"className":882},[],[884],{"type":64,"value":312},{"type":64,"value":886},". The cost is one more type param; the cost of\n",{"type":59,"tag":78,"props":888,"children":890},{"className":889},[],[891],{"type":64,"value":857},{"type":64,"value":893}," is permanent shape loss in everything downstream.",{"type":59,"tag":60,"props":895,"children":896},{},[897],{"type":59,"tag":70,"props":898,"children":899},{},[900],{"type":64,"value":901},"Critical rules:",{"type":59,"tag":108,"props":903,"children":904},{},[905,932,989,1009,1055,1091,1201,1284,1302],{"type":59,"tag":112,"props":906,"children":907},{},[908,910,915,917,923,925,930],{"type":64,"value":909},"Every ",{"type":59,"tag":78,"props":911,"children":913},{"className":912},[],[914],{"type":64,"value":857},{"type":64,"value":916}," that flows to a sub-module constructor (",{"type":59,"tag":78,"props":918,"children":920},{"className":919},[],[921],{"type":64,"value":922},"nn.Linear(dim, ...)",{"type":64,"value":924},")\nMUST be ",{"type":59,"tag":78,"props":926,"children":928},{"className":927},[],[929],{"type":64,"value":312},{"type":64,"value":931},". No exceptions.",{"type":59,"tag":112,"props":933,"children":934},{},[935,937,943,944,950,952,957,959,964,966,972,973,979,981,987],{"type":64,"value":936},"Never cast Int to int (",{"type":59,"tag":78,"props":938,"children":940},{"className":939},[],[941],{"type":64,"value":942},"int(dim)",{"type":64,"value":556},{"type":59,"tag":78,"props":945,"children":947},{"className":946},[],[948],{"type":64,"value":949},"self.x = int(dim)",{"type":64,"value":951},") — ",{"type":59,"tag":78,"props":953,"children":955},{"className":954},[],[956],{"type":64,"value":312},{"type":64,"value":958}," is a\nsubtype of ",{"type":59,"tag":78,"props":960,"children":962},{"className":961},[],[963],{"type":64,"value":857},{"type":64,"value":965},", so the cast only kills tracking. Exception:\n",{"type":59,"tag":78,"props":967,"children":969},{"className":968},[],[970],{"type":64,"value":971},"bool",{"type":64,"value":396},{"type":59,"tag":78,"props":974,"children":976},{"className":975},[],[977],{"type":64,"value":978},"float",{"type":64,"value":980}," conversion is necessary, but ",{"type":59,"tag":78,"props":982,"children":984},{"className":983},[],[985],{"type":64,"value":986},"int * Int",{"type":64,"value":988}," produces\nUnknown — check whether it reaches tensor shapes before fixing. Don't\nreplace with if\u002Felse branching (union of concrete expressions is worse\nthan one Unknown).",{"type":59,"tag":112,"props":990,"children":991},{},[992,994,1000,1001,1007],{"type":64,"value":993},"Derived dims use expressions (",{"type":59,"tag":78,"props":995,"children":997},{"className":996},[],[998],{"type":64,"value":999},"D \u002F\u002F NHead",{"type":64,"value":556},{"type":59,"tag":78,"props":1002,"children":1004},{"className":1003},[],[1005],{"type":64,"value":1006},"4 * ES",{"type":64,"value":1008},"), not independent\ntype params. Only independent degrees of freedom get type params.",{"type":59,"tag":112,"props":1010,"children":1011},{},[1012,1024,1026,1031,1033,1039,1041,1046,1048,1053],{"type":59,"tag":70,"props":1013,"children":1014},{},[1015,1017,1023],{"type":64,"value":1016},"Dimensions from ",{"type":59,"tag":78,"props":1018,"children":1020},{"className":1019},[],[1021],{"type":64,"value":1022},"list[int]",{"type":64,"value":810},{"type":64,"value":1025}," ",{"type":59,"tag":78,"props":1027,"children":1029},{"className":1028},[],[1030],{"type":64,"value":1022},{"type":64,"value":1032}," element access (e.g.,\n",{"type":59,"tag":78,"props":1034,"children":1036},{"className":1035},[],[1037],{"type":64,"value":1038},"hidden_units[-1]",{"type":64,"value":1040},") erases the concrete value to ",{"type":59,"tag":78,"props":1042,"children":1044},{"className":1043},[],[1045],{"type":64,"value":857},{"type":64,"value":1047},". Add an explicit\n",{"type":59,"tag":78,"props":1049,"children":1051},{"className":1050},[],[1052],{"type":64,"value":312},{"type":64,"value":1054}," field to the config or constructor for that value.",{"type":59,"tag":112,"props":1056,"children":1057},{},[1058,1060,1066,1068,1074,1076,1082,1084,1090],{"type":64,"value":1059},"Use ",{"type":59,"tag":78,"props":1061,"children":1063},{"className":1062},[],[1064],{"type":64,"value":1065},"nn.Buffer",{"type":64,"value":1067}," and ",{"type":59,"tag":78,"props":1069,"children":1071},{"className":1070},[],[1072],{"type":64,"value":1073},"nn.Parameter",{"type":64,"value":1075},", not ",{"type":59,"tag":78,"props":1077,"children":1079},{"className":1078},[],[1080],{"type":64,"value":1081},"register_buffer",{"type":64,"value":1083},"\u002F\n",{"type":59,"tag":78,"props":1085,"children":1087},{"className":1086},[],[1088],{"type":64,"value":1089},"register_parameter",{"type":64,"value":810},{"type":59,"tag":112,"props":1092,"children":1093},{},[1094,1099,1101,1107,1109,1115,1117,1123,1125,1130,1132,1179,1183,1185,1191,1193,1199],{"type":59,"tag":70,"props":1095,"children":1096},{},[1097],{"type":64,"value":1098},"Bridge dims.",{"type":64,"value":1100}," When part of the model is untracked (e.g., features\nbuilt via ",{"type":59,"tag":78,"props":1102,"children":1104},{"className":1103},[],[1105],{"type":64,"value":1106},"nn.Sequential(*list)",{"type":64,"value":1108},"), look for dimensions that connect\nthe untracked section to tracked downstream modules. For example, if\nfeatures output feeds a Linear classifier, the Linear's ",{"type":59,"tag":78,"props":1110,"children":1112},{"className":1111},[],[1113],{"type":64,"value":1114},"in_features",{"type":64,"value":1116},"\nis a bridge dim — making it a class type param enables annotation\nfallback to recover a shaped type (e.g., ",{"type":59,"tag":78,"props":1118,"children":1120},{"className":1119},[],[1121],{"type":64,"value":1122},"Tensor[[B, LastC]]",{"type":64,"value":1124},") that\nthen flows naturally through downstream ops. Without it, annotation\nfallback can only recover bare ",{"type":59,"tag":78,"props":1126,"children":1128},{"className":1127},[],[1129],{"type":64,"value":616},{"type":64,"value":1131}," or batch-only shapes.",{"type":59,"tag":533,"props":1133,"children":1135},{"className":639,"code":1134,"language":25,"meta":541,"style":541},"class Model[NC: IntVar, LC: IntVar](nn.Module):\n    def __init__(self, num_classes: Int[NC] = 1000,\n                 last_channel: Int[LC] = 1280):\n        ...\n        self.classifier = nn.Linear(last_channel, num_classes)\n",[1136],{"type":59,"tag":78,"props":1137,"children":1138},{"__ignoreMap":541},[1139,1147,1155,1163,1171],{"type":59,"tag":646,"props":1140,"children":1141},{"class":648,"line":649},[1142],{"type":59,"tag":646,"props":1143,"children":1144},{},[1145],{"type":64,"value":1146},"class Model[NC: IntVar, LC: IntVar](nn.Module):\n",{"type":59,"tag":646,"props":1148,"children":1149},{"class":648,"line":658},[1150],{"type":59,"tag":646,"props":1151,"children":1152},{},[1153],{"type":64,"value":1154},"    def __init__(self, num_classes: Int[NC] = 1000,\n",{"type":59,"tag":646,"props":1156,"children":1157},{"class":648,"line":667},[1158],{"type":59,"tag":646,"props":1159,"children":1160},{},[1161],{"type":64,"value":1162},"                 last_channel: Int[LC] = 1280):\n",{"type":59,"tag":646,"props":1164,"children":1165},{"class":648,"line":676},[1166],{"type":59,"tag":646,"props":1167,"children":1168},{},[1169],{"type":64,"value":1170},"        ...\n",{"type":59,"tag":646,"props":1172,"children":1173},{"class":648,"line":685},[1174],{"type":59,"tag":646,"props":1175,"children":1176},{},[1177],{"type":64,"value":1178},"        self.classifier = nn.Linear(last_channel, num_classes)\n",{"type":59,"tag":1180,"props":1181,"children":1182},"br",{},[],{"type":64,"value":1184},"Here ",{"type":59,"tag":78,"props":1186,"children":1188},{"className":1187},[],[1189],{"type":64,"value":1190},"LC",{"type":64,"value":1192}," bridges the untracked feature extractor to the typed\nclassifier, recovering ",{"type":59,"tag":78,"props":1194,"children":1196},{"className":1195},[],[1197],{"type":64,"value":1198},"Tensor[[B, NC]]",{"type":64,"value":1200}," at the output.",{"type":59,"tag":112,"props":1202,"children":1203},{},[1204,1215,1217,1223,1225,1230,1231,1236,1238,1244,1245,1251,1253,1259,1261,1267,1269,1275,1277,1282],{"type":59,"tag":70,"props":1205,"children":1206},{},[1207,1213],{"type":59,"tag":78,"props":1208,"children":1210},{"className":1209},[],[1211],{"type":64,"value":1212},"Int[X] | None",{"type":64,"value":1214}," for optional dimensions.",{"type":64,"value":1216}," When a parameter is\n",{"type":59,"tag":78,"props":1218,"children":1220},{"className":1219},[],[1221],{"type":64,"value":1222},"Optional[int]",{"type":64,"value":1224}," but flows to tensor shapes when present, type it as\n",{"type":59,"tag":78,"props":1226,"children":1228},{"className":1227},[],[1229],{"type":64,"value":1212},{"type":64,"value":1075},{"type":59,"tag":78,"props":1232,"children":1234},{"className":1233},[],[1235],{"type":64,"value":1222},{"type":64,"value":1237},". Example:\n",{"type":59,"tag":78,"props":1239,"children":1241},{"className":1240},[],[1242],{"type":64,"value":1243},"rank_k: Optional[int]",{"type":64,"value":731},{"type":59,"tag":78,"props":1246,"children":1248},{"className":1247},[],[1249],{"type":64,"value":1250},"rank_k: Int[RK] | None",{"type":64,"value":1252},". In the forward\nmethod, narrow with ",{"type":59,"tag":78,"props":1254,"children":1256},{"className":1255},[],[1257],{"type":64,"value":1258},"if rank_k is not None:",{"type":64,"value":1260}," — the checker then\ntreats ",{"type":59,"tag":78,"props":1262,"children":1264},{"className":1263},[],[1265],{"type":64,"value":1266},"rank_k",{"type":64,"value":1268}," as ",{"type":59,"tag":78,"props":1270,"children":1272},{"className":1271},[],[1273],{"type":64,"value":1274},"Int[RK]",{"type":64,"value":1276}," inside the branch. Leaving it as\n",{"type":59,"tag":78,"props":1278,"children":1280},{"className":1279},[],[1281],{"type":64,"value":1222},{"type":64,"value":1283}," permanently loses tracking in every downstream op.",{"type":59,"tag":112,"props":1285,"children":1286},{},[1287,1292,1294,1300],{"type":59,"tag":70,"props":1288,"children":1289},{},[1290],{"type":64,"value":1291},"Parameterized config dataclasses.",{"type":64,"value":1293}," When multiple modules consume\ndimensions from the same ",{"type":59,"tag":78,"props":1295,"children":1297},{"className":1296},[],[1298],{"type":64,"value":1299},"@dataclass",{"type":64,"value":1301}," config, note it — Step 2\nshows how to parameterize the config so dims propagate across\nmodule boundaries.",{"type":59,"tag":112,"props":1303,"children":1304},{},[1305,1310,1312,1318,1320,1326,1328,1334,1336,1341,1343,1349,1351,1488,1491,1493,1498,1500,1505,1507,1512],{"type":59,"tag":70,"props":1306,"children":1307},{},[1308],{"type":64,"value":1309},"Lazy-initialized buffer attributes.",{"type":64,"value":1311}," An attribute's type is fixed\nat the declaration, not at later assignments. Declaring\n",{"type":59,"tag":78,"props":1313,"children":1315},{"className":1314},[],[1316],{"type":64,"value":1317},"self.x: Tensor | None = None",{"type":64,"value":1319}," and assigning a real tensor in a\nsetup hook (e.g., ",{"type":59,"tag":78,"props":1321,"children":1323},{"className":1322},[],[1324],{"type":64,"value":1325},"setup_caches",{"type":64,"value":1327},") loses the shape forever — every\nread site sees ",{"type":59,"tag":78,"props":1329,"children":1331},{"className":1330},[],[1332],{"type":64,"value":1333},"Tensor | None",{"type":64,"value":1335},", and the best you get after a None\ncheck is bare ",{"type":59,"tag":78,"props":1337,"children":1339},{"className":1338},[],[1340],{"type":64,"value":616},{"type":64,"value":1342},". If the field is always assigned before\nfirst use, initialize it eagerly in ",{"type":59,"tag":78,"props":1344,"children":1346},{"className":1345},[],[1347],{"type":64,"value":1348},"__init__",{"type":64,"value":1350}," with the real shape:",{"type":59,"tag":533,"props":1352,"children":1354},{"className":639,"code":1353,"language":25,"meta":541,"style":541},"# Bad: causal_mask is Tensor | None everywhere; shape is lost\nclass Attention(nn.Module):\n    def __init__(self, ...):\n        self.causal_mask: Tensor | None = None\n    def setup_caches(self, max_seq_len: int):\n        self.causal_mask = torch.tril(\n            torch.ones(max_seq_len, max_seq_len)\n        )\n\n# Good: causal_mask is Tensor[[MS, MS]] from declaration\nclass Attention[MS: IntVar](nn.Module):\n    def __init__(self, max_seq_len: Int[MS], ...):\n        self.causal_mask: Tensor[[MS, MS]] = torch.zeros(\n            max_seq_len, max_seq_len\n        )\n",[1355],{"type":59,"tag":78,"props":1356,"children":1357},{"__ignoreMap":541},[1358,1366,1374,1382,1390,1398,1407,1416,1425,1435,1444,1453,1462,1471,1480],{"type":59,"tag":646,"props":1359,"children":1360},{"class":648,"line":649},[1361],{"type":59,"tag":646,"props":1362,"children":1363},{},[1364],{"type":64,"value":1365},"# Bad: causal_mask is Tensor | None everywhere; shape is lost\n",{"type":59,"tag":646,"props":1367,"children":1368},{"class":648,"line":658},[1369],{"type":59,"tag":646,"props":1370,"children":1371},{},[1372],{"type":64,"value":1373},"class Attention(nn.Module):\n",{"type":59,"tag":646,"props":1375,"children":1376},{"class":648,"line":667},[1377],{"type":59,"tag":646,"props":1378,"children":1379},{},[1380],{"type":64,"value":1381},"    def __init__(self, ...):\n",{"type":59,"tag":646,"props":1383,"children":1384},{"class":648,"line":676},[1385],{"type":59,"tag":646,"props":1386,"children":1387},{},[1388],{"type":64,"value":1389},"        self.causal_mask: Tensor | None = None\n",{"type":59,"tag":646,"props":1391,"children":1392},{"class":648,"line":685},[1393],{"type":59,"tag":646,"props":1394,"children":1395},{},[1396],{"type":64,"value":1397},"    def setup_caches(self, max_seq_len: int):\n",{"type":59,"tag":646,"props":1399,"children":1401},{"class":648,"line":1400},6,[1402],{"type":59,"tag":646,"props":1403,"children":1404},{},[1405],{"type":64,"value":1406},"        self.causal_mask = torch.tril(\n",{"type":59,"tag":646,"props":1408,"children":1410},{"class":648,"line":1409},7,[1411],{"type":59,"tag":646,"props":1412,"children":1413},{},[1414],{"type":64,"value":1415},"            torch.ones(max_seq_len, max_seq_len)\n",{"type":59,"tag":646,"props":1417,"children":1419},{"class":648,"line":1418},8,[1420],{"type":59,"tag":646,"props":1421,"children":1422},{},[1423],{"type":64,"value":1424},"        )\n",{"type":59,"tag":646,"props":1426,"children":1428},{"class":648,"line":1427},9,[1429],{"type":59,"tag":646,"props":1430,"children":1432},{"emptyLinePlaceholder":1431},true,[1433],{"type":64,"value":1434},"\n",{"type":59,"tag":646,"props":1436,"children":1438},{"class":648,"line":1437},10,[1439],{"type":59,"tag":646,"props":1440,"children":1441},{},[1442],{"type":64,"value":1443},"# Good: causal_mask is Tensor[[MS, MS]] from declaration\n",{"type":59,"tag":646,"props":1445,"children":1447},{"class":648,"line":1446},11,[1448],{"type":59,"tag":646,"props":1449,"children":1450},{},[1451],{"type":64,"value":1452},"class Attention[MS: IntVar](nn.Module):\n",{"type":59,"tag":646,"props":1454,"children":1456},{"class":648,"line":1455},12,[1457],{"type":59,"tag":646,"props":1458,"children":1459},{},[1460],{"type":64,"value":1461},"    def __init__(self, max_seq_len: Int[MS], ...):\n",{"type":59,"tag":646,"props":1463,"children":1465},{"class":648,"line":1464},13,[1466],{"type":59,"tag":646,"props":1467,"children":1468},{},[1469],{"type":64,"value":1470},"        self.causal_mask: Tensor[[MS, MS]] = torch.zeros(\n",{"type":59,"tag":646,"props":1472,"children":1474},{"class":648,"line":1473},14,[1475],{"type":59,"tag":646,"props":1476,"children":1477},{},[1478],{"type":64,"value":1479},"            max_seq_len, max_seq_len\n",{"type":59,"tag":646,"props":1481,"children":1483},{"class":648,"line":1482},15,[1484],{"type":59,"tag":646,"props":1485,"children":1486},{},[1487],{"type":64,"value":1424},{"type":59,"tag":1180,"props":1489,"children":1490},{},[],{"type":64,"value":1492},"Reserve ",{"type":59,"tag":78,"props":1494,"children":1496},{"className":1495},[],[1497],{"type":64,"value":1333},{"type":64,"value":1499}," for fields that may ",{"type":59,"tag":100,"props":1501,"children":1502},{},[1503],{"type":64,"value":1504},"genuinely",{"type":64,"value":1506}," never be\nset. If late init is unavoidable because the shape depends on a\nruntime decision, accept that bare ",{"type":59,"tag":78,"props":1508,"children":1510},{"className":1509},[],[1511],{"type":64,"value":616},{"type":64,"value":1513}," post-narrow is the\nright answer and document it as a Step 4 receipt.",{"type":59,"tag":280,"props":1515,"children":1517},{"id":1516},"step-2-type-the-constructor",[1518],{"type":64,"value":1519},"Step 2: Type the constructor",{"type":59,"tag":60,"props":1521,"children":1522},{},[1523,1525,1530,1532,1537],{"type":64,"value":1524},"Write ",{"type":59,"tag":78,"props":1526,"children":1528},{"className":1527},[],[1529],{"type":64,"value":1348},{"type":64,"value":1531}," with the ",{"type":59,"tag":78,"props":1533,"children":1535},{"className":1534},[],[1536],{"type":64,"value":312},{"type":64,"value":1538}," params from Step 1. Construct sub-modules\nusing those Int params — they get typed automatically.",{"type":59,"tag":60,"props":1540,"children":1541},{},[1542,1547,1548,1554,1556,1562],{"type":59,"tag":70,"props":1543,"children":1544},{},[1545],{"type":64,"value":1546},"Default values for Int params:",{"type":64,"value":1025},{"type":59,"tag":78,"props":1549,"children":1551},{"className":1550},[],[1552],{"type":64,"value":1553},"Literal[0]",{"type":64,"value":1555}," is not assignable to\n",{"type":59,"tag":78,"props":1557,"children":1559},{"className":1558},[],[1560],{"type":64,"value":1561},"Int[X]",{"type":64,"value":1563}," as a default. Use PEP 696 type-parameter defaults instead:",{"type":59,"tag":533,"props":1565,"children":1567},{"className":639,"code":1566,"language":25,"meta":541,"style":541},"# Won't work — Literal[1000] not assignable to Int[NC]:\ndef __init__(self, num_classes: Int[NC] = 1000): ...\n\n# Works — NC defaults to 1000 at the type level (bound + PEP 696 default):\nclass Model[NC: IntVar = 1000](nn.Module):\n    def __init__(self, num_classes: Int[NC] = 1000): ...\n",[1568],{"type":59,"tag":78,"props":1569,"children":1570},{"__ignoreMap":541},[1571,1579,1587,1594,1602,1610],{"type":59,"tag":646,"props":1572,"children":1573},{"class":648,"line":649},[1574],{"type":59,"tag":646,"props":1575,"children":1576},{},[1577],{"type":64,"value":1578},"# Won't work — Literal[1000] not assignable to Int[NC]:\n",{"type":59,"tag":646,"props":1580,"children":1581},{"class":648,"line":658},[1582],{"type":59,"tag":646,"props":1583,"children":1584},{},[1585],{"type":64,"value":1586},"def __init__(self, num_classes: Int[NC] = 1000): ...\n",{"type":59,"tag":646,"props":1588,"children":1589},{"class":648,"line":667},[1590],{"type":59,"tag":646,"props":1591,"children":1592},{"emptyLinePlaceholder":1431},[1593],{"type":64,"value":1434},{"type":59,"tag":646,"props":1595,"children":1596},{"class":648,"line":676},[1597],{"type":59,"tag":646,"props":1598,"children":1599},{},[1600],{"type":64,"value":1601},"# Works — NC defaults to 1000 at the type level (bound + PEP 696 default):\n",{"type":59,"tag":646,"props":1603,"children":1604},{"class":648,"line":685},[1605],{"type":59,"tag":646,"props":1606,"children":1607},{},[1608],{"type":64,"value":1609},"class Model[NC: IntVar = 1000](nn.Module):\n",{"type":59,"tag":646,"props":1611,"children":1612},{"class":648,"line":1400},[1613],{"type":59,"tag":646,"props":1614,"children":1615},{},[1616],{"type":64,"value":1617},"    def __init__(self, num_classes: Int[NC] = 1000): ...\n",{"type":59,"tag":60,"props":1619,"children":1620},{},[1621],{"type":59,"tag":70,"props":1622,"children":1623},{},[1624],{"type":64,"value":1625},"Constructor patterns that break shape tracking:",{"type":59,"tag":108,"props":1627,"children":1628},{},[1629,1665,1688,1717],{"type":59,"tag":112,"props":1630,"children":1631},{},[1632,1641,1643,1648,1650,1656,1658,1664],{"type":59,"tag":70,"props":1633,"children":1634},{},[1635],{"type":59,"tag":78,"props":1636,"children":1638},{"className":1637},[],[1639],{"type":64,"value":1640},"nn.Sequential(*list_var)",{"type":64,"value":1642}," erases module types — the Sequential\nreturns bare ",{"type":59,"tag":78,"props":1644,"children":1646},{"className":1645},[],[1647],{"type":64,"value":616},{"type":64,"value":1649},". Only ",{"type":59,"tag":78,"props":1651,"children":1653},{"className":1652},[],[1654],{"type":64,"value":1655},"nn.Sequential(M1(), M2(), M3())",{"type":64,"value":1657}," with\ndirect arguments is tracked. Extract shape-changing modules (Linear,\nConv2d) as individual attributes and chain in ",{"type":59,"tag":78,"props":1659,"children":1661},{"className":1660},[],[1662],{"type":64,"value":1663},"forward",{"type":64,"value":810},{"type":59,"tag":112,"props":1666,"children":1667},{},[1668,1679,1681,1686],{"type":59,"tag":70,"props":1669,"children":1670},{},[1671,1673],{"type":64,"value":1672},"Factory functions returning ",{"type":59,"tag":78,"props":1674,"children":1676},{"className":1675},[],[1677],{"type":64,"value":1678},"nn.Sequential",{"type":64,"value":1680}," erase all type\nparameters at the function boundary. Use a class with a typed\n",{"type":59,"tag":78,"props":1682,"children":1684},{"className":1683},[],[1685],{"type":64,"value":1663},{"type":64,"value":1687}," method instead.",{"type":59,"tag":112,"props":1689,"children":1690},{},[1691,1700,1702,1708,1710,1715],{"type":59,"tag":70,"props":1692,"children":1693},{},[1694],{"type":59,"tag":78,"props":1695,"children":1697},{"className":1696},[],[1698],{"type":64,"value":1699},"getattr(nn, name)()",{"type":64,"value":1701}," returns ",{"type":59,"tag":78,"props":1703,"children":1705},{"className":1704},[],[1706],{"type":64,"value":1707},"Any",{"type":64,"value":1709},". Replace with a union of\ntyped ",{"type":59,"tag":78,"props":1711,"children":1713},{"className":1712},[],[1714],{"type":64,"value":386},{"type":64,"value":1716}," subclass types.",{"type":59,"tag":112,"props":1718,"children":1719},{},[1720,1725,1727,1733,1735,1740,1742,1747],{"type":59,"tag":70,"props":1721,"children":1722},{},[1723],{"type":64,"value":1724},"Method-level type params on class fields.",{"type":64,"value":1726}," If a method creates\nshaped tensors assigned to ",{"type":59,"tag":78,"props":1728,"children":1730},{"className":1729},[],[1731],{"type":64,"value":1732},"self.field",{"type":64,"value":1734},", the field can't carry the\nmethod's type params — it reverts to bare ",{"type":59,"tag":78,"props":1736,"children":1738},{"className":1737},[],[1739],{"type":64,"value":616},{"type":64,"value":1741},". Move creation\nto ",{"type":59,"tag":78,"props":1743,"children":1745},{"className":1744},[],[1746],{"type":64,"value":1348},{"type":64,"value":1748}," so type params become class-level.",{"type":59,"tag":60,"props":1750,"children":1751},{},[1752,1756,1758,1763],{"type":59,"tag":70,"props":1753,"children":1754},{},[1755],{"type":64,"value":1291},{"type":64,"value":1757}," When a ",{"type":59,"tag":78,"props":1759,"children":1761},{"className":1760},[],[1762],{"type":64,"value":1299},{"type":64,"value":1764}," holds\ndimension hyperparameters consumed by multiple modules, make it\ngeneric so dims propagate through constructors:",{"type":59,"tag":533,"props":1766,"children":1768},{"className":639,"code":1767,"language":25,"meta":541,"style":541},"@dataclass\nclass Config[D: IntVar, NHead: IntVar, VocabSize: IntVar]:\n    dim: Int[D]\n    n_head: Int[NHead]\n    vocab_size: Int[VocabSize]\n    dropout: float = 0.0\n",[1769],{"type":59,"tag":78,"props":1770,"children":1771},{"__ignoreMap":541},[1772,1780,1788,1796,1804,1812],{"type":59,"tag":646,"props":1773,"children":1774},{"class":648,"line":649},[1775],{"type":59,"tag":646,"props":1776,"children":1777},{},[1778],{"type":64,"value":1779},"@dataclass\n",{"type":59,"tag":646,"props":1781,"children":1782},{"class":648,"line":658},[1783],{"type":59,"tag":646,"props":1784,"children":1785},{},[1786],{"type":64,"value":1787},"class Config[D: IntVar, NHead: IntVar, VocabSize: IntVar]:\n",{"type":59,"tag":646,"props":1789,"children":1790},{"class":648,"line":667},[1791],{"type":59,"tag":646,"props":1792,"children":1793},{},[1794],{"type":64,"value":1795},"    dim: Int[D]\n",{"type":59,"tag":646,"props":1797,"children":1798},{"class":648,"line":676},[1799],{"type":59,"tag":646,"props":1800,"children":1801},{},[1802],{"type":64,"value":1803},"    n_head: Int[NHead]\n",{"type":59,"tag":646,"props":1805,"children":1806},{"class":648,"line":685},[1807],{"type":59,"tag":646,"props":1808,"children":1809},{},[1810],{"type":64,"value":1811},"    vocab_size: Int[VocabSize]\n",{"type":59,"tag":646,"props":1813,"children":1814},{"class":648,"line":1400},[1815],{"type":59,"tag":646,"props":1816,"children":1817},{},[1818],{"type":64,"value":1819},"    dropout: float = 0.0\n",{"type":59,"tag":60,"props":1821,"children":1822},{},[1823,1825,1830],{"type":64,"value":1824},"Modules extract only the params they need using ",{"type":59,"tag":78,"props":1826,"children":1828},{"className":1827},[],[1829],{"type":64,"value":1707},{"type":64,"value":1831}," for the rest:",{"type":59,"tag":533,"props":1833,"children":1835},{"className":639,"code":1834,"language":25,"meta":541,"style":541},"class MLP[D: IntVar](nn.Module):\n    def __init__(self, config: Config[D, Any, Any]):\n        super().__init__()\n        self.fc = nn.Linear(config.dim, 4 * config.dim)\n",[1836],{"type":59,"tag":78,"props":1837,"children":1838},{"__ignoreMap":541},[1839,1847,1855,1863],{"type":59,"tag":646,"props":1840,"children":1841},{"class":648,"line":649},[1842],{"type":59,"tag":646,"props":1843,"children":1844},{},[1845],{"type":64,"value":1846},"class MLP[D: IntVar](nn.Module):\n",{"type":59,"tag":646,"props":1848,"children":1849},{"class":648,"line":658},[1850],{"type":59,"tag":646,"props":1851,"children":1852},{},[1853],{"type":64,"value":1854},"    def __init__(self, config: Config[D, Any, Any]):\n",{"type":59,"tag":646,"props":1856,"children":1857},{"class":648,"line":667},[1858],{"type":59,"tag":646,"props":1859,"children":1860},{},[1861],{"type":64,"value":1862},"        super().__init__()\n",{"type":59,"tag":646,"props":1864,"children":1865},{"class":648,"line":676},[1866],{"type":59,"tag":646,"props":1867,"children":1868},{},[1869],{"type":64,"value":1870},"        self.fc = nn.Linear(config.dim, 4 * config.dim)\n",{"type":59,"tag":60,"props":1872,"children":1873},{},[1874],{"type":64,"value":1875},"Without this, each module must independently accept and thread\nevery dim through its constructor — error-prone and verbose.",{"type":59,"tag":60,"props":1877,"children":1878},{},[1879,1881,1887],{"type":64,"value":1880},"If the original config had default values (e.g., ",{"type":59,"tag":78,"props":1882,"children":1884},{"className":1883},[],[1885],{"type":64,"value":1886},"dim: int = 768",{"type":64,"value":1888},"),\ncombine the two patterns above — give the dataclass type params PEP\n696 defaults so callers can omit dims:",{"type":59,"tag":533,"props":1890,"children":1892},{"className":639,"code":1891,"language":25,"meta":541,"style":541},"@dataclass\nclass Config[D: IntVar = 768, NHead: IntVar = 12, VocabSize: IntVar = 50257]:\n    dim: Int[D] = 768  # type: ignore[bad-assignment]\n    n_head: Int[NHead] = 12  # type: ignore[bad-assignment]\n    vocab_size: Int[VocabSize] = 50257  # type: ignore[bad-assignment]\n    dropout: float = 0.0\n",[1893],{"type":59,"tag":78,"props":1894,"children":1895},{"__ignoreMap":541},[1896,1903,1911,1919,1927,1935],{"type":59,"tag":646,"props":1897,"children":1898},{"class":648,"line":649},[1899],{"type":59,"tag":646,"props":1900,"children":1901},{},[1902],{"type":64,"value":1779},{"type":59,"tag":646,"props":1904,"children":1905},{"class":648,"line":658},[1906],{"type":59,"tag":646,"props":1907,"children":1908},{},[1909],{"type":64,"value":1910},"class Config[D: IntVar = 768, NHead: IntVar = 12, VocabSize: IntVar = 50257]:\n",{"type":59,"tag":646,"props":1912,"children":1913},{"class":648,"line":667},[1914],{"type":59,"tag":646,"props":1915,"children":1916},{},[1917],{"type":64,"value":1918},"    dim: Int[D] = 768  # type: ignore[bad-assignment]\n",{"type":59,"tag":646,"props":1920,"children":1921},{"class":648,"line":676},[1922],{"type":59,"tag":646,"props":1923,"children":1924},{},[1925],{"type":64,"value":1926},"    n_head: Int[NHead] = 12  # type: ignore[bad-assignment]\n",{"type":59,"tag":646,"props":1928,"children":1929},{"class":648,"line":685},[1930],{"type":59,"tag":646,"props":1931,"children":1932},{},[1933],{"type":64,"value":1934},"    vocab_size: Int[VocabSize] = 50257  # type: ignore[bad-assignment]\n",{"type":59,"tag":646,"props":1936,"children":1937},{"class":648,"line":1400},[1938],{"type":59,"tag":646,"props":1939,"children":1940},{},[1941],{"type":64,"value":1819},{"type":59,"tag":60,"props":1943,"children":1944},{},[1945],{"type":64,"value":1946},"Two different defaults are at play here, and only one is clean:",{"type":59,"tag":108,"props":1948,"children":1949},{},[1950,1969],{"type":59,"tag":112,"props":1951,"children":1952},{},[1953,1955,1960,1961,1967],{"type":64,"value":1954},"The ",{"type":59,"tag":70,"props":1956,"children":1957},{},[1958],{"type":64,"value":1959},"PEP 696 defaults on the type params",{"type":64,"value":723},{"type":59,"tag":78,"props":1962,"children":1964},{"className":1963},[],[1965],{"type":64,"value":1966},"[D: IntVar = 768, ...]",{"type":64,"value":1968},") are\nwhat let callers omit dims — those need no ignore.",{"type":59,"tag":112,"props":1970,"children":1971},{},[1972,1973,1978,1979,1985,1987,1993,1995,2000,2002,2008,2010,2016,2018,2023,2025,2031,2033,2038],{"type":64,"value":1954},{"type":59,"tag":70,"props":1974,"children":1975},{},[1976],{"type":64,"value":1977},"dataclass field literal defaults",{"type":64,"value":723},{"type":59,"tag":78,"props":1980,"children":1982},{"className":1981},[],[1983],{"type":64,"value":1984},"dim: Int[D] = 768",{"type":64,"value":1986},") still need\n",{"type":59,"tag":78,"props":1988,"children":1990},{"className":1989},[],[1991],{"type":64,"value":1992},"# type: ignore[bad-assignment]",{"type":64,"value":1994},", because a plain ",{"type":59,"tag":78,"props":1996,"children":1998},{"className":1997},[],[1999],{"type":64,"value":857},{"type":64,"value":2001}," literal is not\nassignable to ",{"type":59,"tag":78,"props":2003,"children":2005},{"className":2004},[],[2006],{"type":64,"value":2007},"Int[D]",{"type":64,"value":2009},". This is the accepted corpus pattern (see\n",{"type":59,"tag":78,"props":2011,"children":2013},{"className":2012},[],[2014],{"type":64,"value":2015},"examples\u002Ffinalmlp.py",{"type":64,"value":2017},"). Note that ",{"type":59,"tag":100,"props":2019,"children":2020},{},[2021],{"type":64,"value":2022},"constructor",{"type":64,"value":2024},"-parameter defaults\n(",{"type":59,"tag":78,"props":2026,"children":2028},{"className":2027},[],[2029],{"type":64,"value":2030},"def __init__(self, num_classes: Int[NC] = 1000)",{"type":64,"value":2032},") do ",{"type":59,"tag":70,"props":2034,"children":2035},{},[2036],{"type":64,"value":2037},"not",{"type":64,"value":2039}," need the\nignore — only dataclass field defaults do.",{"type":59,"tag":60,"props":2041,"children":2042},{},[2043,2045,2051,2053,2059,2061,2067,2068,2074],{"type":64,"value":2044},"Now ",{"type":59,"tag":78,"props":2046,"children":2048},{"className":2047},[],[2049],{"type":64,"value":2050},"Config()",{"type":64,"value":2052}," produces ",{"type":59,"tag":78,"props":2054,"children":2056},{"className":2055},[],[2057],{"type":64,"value":2058},"Config[768, 12, 50257]",{"type":64,"value":2060}," and\n",{"type":59,"tag":78,"props":2062,"children":2064},{"className":2063},[],[2065],{"type":64,"value":2066},"Config(dim=1024)",{"type":64,"value":2052},{"type":59,"tag":78,"props":2069,"children":2071},{"className":2070},[],[2072],{"type":64,"value":2073},"Config[1024, 12, 50257]",{"type":64,"value":2075}," — dims\npropagate even when callers don't pass every parameter.",{"type":59,"tag":60,"props":2077,"children":2078},{},[2079,2084,2086,2091],{"type":59,"tag":70,"props":2080,"children":2081},{},[2082],{"type":64,"value":2083},"DO NOT write the forward method yet.",{"type":64,"value":2085}," The forward signature and\n",{"type":59,"tag":78,"props":2087,"children":2089},{"className":2088},[],[2090],{"type":64,"value":91},{"type":64,"value":2092}," expressions depend on what the checker infers, which you\ndon't know until Step 3.",{"type":59,"tag":60,"props":2094,"children":2095},{},[2096,2098,2103],{"type":64,"value":2097},"Run the checker to verify the constructor compiles. ",{"type":59,"tag":70,"props":2099,"children":2100},{},[2101],{"type":64,"value":2102},"Paste the checker\noutput",{"type":64,"value":2104}," (0 errors, or the errors you need to fix) before proceeding.",{"type":59,"tag":280,"props":2106,"children":2108},{"id":2107},"step-3-probe-the-forward",[2109],{"type":64,"value":2110},"Step 3: Probe the forward",{"type":59,"tag":60,"props":2112,"children":2113},{},[2114,2116,2121,2123,2129,2130,2136,2137,2143],{"type":64,"value":2115},"First, ",{"type":59,"tag":70,"props":2117,"children":2118},{},[2119],{"type":64,"value":2120},"count the local variables",{"type":64,"value":2122}," in the forward method — every\nassignment to a name (e.g., ",{"type":59,"tag":78,"props":2124,"children":2126},{"className":2125},[],[2127],{"type":64,"value":2128},"x = ...",{"type":64,"value":556},{"type":59,"tag":78,"props":2131,"children":2133},{"className":2132},[],[2134],{"type":64,"value":2135},"out = ...",{"type":64,"value":556},{"type":59,"tag":78,"props":2138,"children":2140},{"className":2139},[],[2141],{"type":64,"value":2142},"result = ...",{"type":64,"value":2144},")\nis a local. Write them down.",{"type":59,"tag":60,"props":2146,"children":2147},{},[2148,2150,2155],{"type":64,"value":2149},"Then add ",{"type":59,"tag":78,"props":2151,"children":2153},{"className":2152},[],[2154],{"type":64,"value":83},{"type":64,"value":2156}," on EVERY local variable. Run the checker.",{"type":59,"tag":60,"props":2158,"children":2159},{},[2160,2165],{"type":59,"tag":70,"props":2161,"children":2162},{},[2163],{"type":64,"value":2164},"Paste the results in your response",{"type":64,"value":2166}," using this exact format. Step 4\ntakes this table as input — if you don't have it, you cannot proceed.",{"type":59,"tag":533,"props":2168,"children":2171},{"className":2169,"code":2170,"language":64},[536],"# reveal_type results for ClassName.forward:\n# Locals: N (list them: var1, var2, var3)\n# var1 (line N): Tensor[[B, C, H, W]]  → SHAPED\n# var2 (line M): Tensor                 → BARE — investigate in Step 4\n# var3 (line P): Tensor[[B, D]]         → SHAPED\n",[2172],{"type":59,"tag":78,"props":2173,"children":2174},{"__ignoreMap":541},[2175],{"type":64,"value":2170},{"type":59,"tag":60,"props":2177,"children":2178},{},[2179],{"type":64,"value":2180},"Verify: does the number of reveal_type entries match the local count?\nIf not, you missed some — go back and add them.",{"type":59,"tag":60,"props":2182,"children":2183},{},[2184,2189],{"type":59,"tag":70,"props":2185,"children":2186},{},[2187],{"type":64,"value":2188},"If a reveal_type result contradicts your understanding of the op",{"type":64,"value":2190},"\n(e.g., spatial dims unchanged after a strided conv, or a shaped op\nreturning bare), write a small isolating test, run the checker, and\nconfirm the behavior before proceeding. Either your understanding is\nwrong (update your mental model) or the checker has a simplification\nyou should document.",{"type":59,"tag":60,"props":2192,"children":2193},{},[2194,2196,2201],{"type":64,"value":2195},"This table is your Step 4 input. Do not write ",{"type":59,"tag":78,"props":2197,"children":2199},{"className":2198},[],[2200],{"type":64,"value":91},{"type":64,"value":2202}," until Step 4\nis complete for every BARE entry. The results tell you:",{"type":59,"tag":108,"props":2204,"children":2205},{},[2206,2218],{"type":59,"tag":112,"props":2207,"children":2208},{},[2209,2211,2216],{"type":64,"value":2210},"Shaped type → the checker tracks this op. Write ",{"type":59,"tag":78,"props":2212,"children":2214},{"className":2213},[],[2215],{"type":64,"value":91},{"type":64,"value":2217}," in Step 5.",{"type":59,"tag":112,"props":2219,"children":2220},{},[2221,2223,2228],{"type":64,"value":2222},"Bare ",{"type":59,"tag":78,"props":2224,"children":2226},{"className":2225},[],[2227],{"type":64,"value":616},{"type":64,"value":2229}," → shape lost. Investigate in Step 4 before deciding.",{"type":59,"tag":280,"props":2231,"children":2233},{"id":2232},"step-4-restructure-for-tracking",[2234],{"type":64,"value":2235},"Step 4: Restructure for tracking",{"type":59,"tag":60,"props":2237,"children":2238},{},[2239,2241,2246],{"type":64,"value":2240},"Many patterns that LOOK dynamic have trackable substructure.\nConditional branching over matmul\u002Fbmm chains, for example, is fully\ntrackable if the dimension values are ",{"type":59,"tag":78,"props":2242,"children":2244},{"className":2243},[],[2245],{"type":64,"value":312},{"type":64,"value":2247},"-typed.",{"type":59,"tag":60,"props":2249,"children":2250},{},[2251,2253,2258],{"type":64,"value":2252},"For EACH bare ",{"type":59,"tag":78,"props":2254,"children":2256},{"className":2255},[],[2257],{"type":64,"value":616},{"type":64,"value":2259}," from Step 3, attempt ALL applicable restructurings\nbefore falling back to typed interface:",{"type":59,"tag":60,"props":2261,"children":2262},{},[2263,2265,2284,2286,2291,2293,2299],{"type":64,"value":2264},"□ ",{"type":59,"tag":70,"props":2266,"children":2267},{},[2268,2274,2276,2282],{"type":59,"tag":78,"props":2269,"children":2271},{"className":2270},[],[2272],{"type":64,"value":2273},"int()",{"type":64,"value":2275}," or ",{"type":59,"tag":78,"props":2277,"children":2279},{"className":2278},[],[2280],{"type":64,"value":2281},"round()",{"type":64,"value":2283}," wrapping a Int value?",{"type":64,"value":2285}," Remove it. If the\nargument is already int-compatible (e.g., ",{"type":59,"tag":78,"props":2287,"children":2289},{"className":2288},[],[2290],{"type":64,"value":2281},{"type":64,"value":2292}," on an integer\n",{"type":59,"tag":78,"props":2294,"children":2296},{"className":2295},[],[2297],{"type":64,"value":2298},"expand_ratio",{"type":64,"value":2300},"), the wrapper is a no-op that kills tracking.",{"type":59,"tag":60,"props":2302,"children":2303},{},[2304,2305,2315,2317,2322,2324,2330,2332,2337],{"type":64,"value":2264},{"type":59,"tag":70,"props":2306,"children":2307},{},[2308,2313],{"type":59,"tag":78,"props":2309,"children":2311},{"className":2310},[],[2312],{"type":64,"value":1640},{"type":64,"value":2314},"?",{"type":64,"value":2316}," Extract shape-changing modules\n(Linear, Conv2d, etc.) as individual attributes and chain them in\n",{"type":59,"tag":78,"props":2318,"children":2320},{"className":2319},[],[2321],{"type":64,"value":1663},{"type":64,"value":2323},". Shape-preserving modules (activations, norms, dropout)\ncan remain grouped since their output shape equals their input.\nNote: this applies to ",{"type":59,"tag":78,"props":2325,"children":2327},{"className":2326},[],[2328],{"type":64,"value":2329},"nn.Sequential(*list_variable)",{"type":64,"value":2331}," where the\nmodules come from a list. ",{"type":59,"tag":78,"props":2333,"children":2335},{"className":2334},[],[2336],{"type":64,"value":1655},{"type":64,"value":2338}," with\ndirect arguments IS tracked — don't restructure it.",{"type":59,"tag":60,"props":2340,"children":2341},{},[2342,2343,2353,2355,2361,2363,2369,2371,2377,2379,2385,2386,2392,2394,2399],{"type":64,"value":2264},{"type":59,"tag":70,"props":2344,"children":2345},{},[2346,2351],{"type":59,"tag":78,"props":2347,"children":2349},{"className":2348},[],[2350],{"type":64,"value":1678},{"type":64,"value":2352}," subclass?",{"type":64,"value":2354}," The special handler tracks shapes when\na Sequential is CALLED as an attribute (",{"type":59,"tag":78,"props":2356,"children":2358},{"className":2357},[],[2359],{"type":64,"value":2360},"self.net(x)",{"type":64,"value":2362},"), but NOT when\nforward is inherited from a Sequential base class. Convert subclasses\nto composition: replace ",{"type":59,"tag":78,"props":2364,"children":2366},{"className":2365},[],[2367],{"type":64,"value":2368},"class Foo(nn.Sequential)",{"type":64,"value":2370}," \u002F\n",{"type":59,"tag":78,"props":2372,"children":2374},{"className":2373},[],[2375],{"type":64,"value":2376},"super().__init__(m1, m2, m3)",{"type":64,"value":2378}," with ",{"type":59,"tag":78,"props":2380,"children":2382},{"className":2381},[],[2383],{"type":64,"value":2384},"class Foo(nn.Module)",{"type":64,"value":2370},{"type":59,"tag":78,"props":2387,"children":2389},{"className":2388},[],[2390],{"type":64,"value":2391},"self.net = nn.Sequential(m1, m2, m3)",{"type":64,"value":2393}," and delegate forward to\n",{"type":59,"tag":78,"props":2395,"children":2397},{"className":2396},[],[2398],{"type":64,"value":2360},{"type":64,"value":2400},". This is the minimal change for full shape tracking.",{"type":59,"tag":60,"props":2402,"children":2403},{},[2404,2405,2424,2425,2431,2433,2439,2441,2447,2448,2454],{"type":64,"value":2264},{"type":59,"tag":70,"props":2406,"children":2407},{},[2408,2414,2416,2422],{"type":59,"tag":78,"props":2409,"children":2411},{"className":2410},[],[2412],{"type":64,"value":2413},"list[...]",{"type":64,"value":2415}," where ",{"type":59,"tag":78,"props":2417,"children":2419},{"className":2418},[],[2420],{"type":64,"value":2421},"tuple[...]",{"type":64,"value":2423}," is needed?",{"type":64,"value":1025},{"type":59,"tag":78,"props":2426,"children":2428},{"className":2427},[],[2429],{"type":64,"value":2430},"torch.cat([a, b])",{"type":64,"value":2432},"\nhomogenizes element types. Use ",{"type":59,"tag":78,"props":2434,"children":2436},{"className":2435},[],[2437],{"type":64,"value":2438},"torch.cat((a, b))",{"type":64,"value":2440},". Same for\n",{"type":59,"tag":78,"props":2442,"children":2444},{"className":2443},[],[2445],{"type":64,"value":2446},".split([d, k, k])",{"type":64,"value":731},{"type":59,"tag":78,"props":2449,"children":2451},{"className":2450},[],[2452],{"type":64,"value":2453},".split((d, k, k))",{"type":64,"value":810},{"type":59,"tag":60,"props":2456,"children":2457},{},[2458,2459,2464,2466,2472,2474,2480],{"type":64,"value":2264},{"type":59,"tag":70,"props":2460,"children":2461},{},[2462],{"type":64,"value":2463},"Branch join widening?",{"type":64,"value":2465}," If the first iteration changes shape but\nsubsequent iterations preserve it, separate the first iteration:\n",{"type":59,"tag":78,"props":2467,"children":2469},{"className":2468},[],[2470],{"type":64,"value":2471},"x = layers[0](input)",{"type":64,"value":2473}," then loop over ",{"type":59,"tag":78,"props":2475,"children":2477},{"className":2476},[],[2478],{"type":64,"value":2479},"layers[1:]",{"type":64,"value":2481},". The dual works\ntoo: separate the last iteration if only the final output matters.",{"type":59,"tag":60,"props":2483,"children":2484},{},[2485,2486,2499],{"type":64,"value":2264},{"type":59,"tag":70,"props":2487,"children":2488},{},[2489,2491,2497],{"type":64,"value":2490},"Loop over ",{"type":59,"tag":78,"props":2492,"children":2494},{"className":2493},[],[2495],{"type":64,"value":2496},"ModuleList",{"type":64,"value":2498}," widens tensor type?",{"type":64,"value":2500}," Same fix as branch\njoin: separate the shape-changing iteration from shape-preserving ones.",{"type":59,"tag":60,"props":2502,"children":2503},{},[2504,2505,2524],{"type":64,"value":2264},{"type":59,"tag":70,"props":2506,"children":2507},{},[2508,2510,2516,2517,2523],{"type":64,"value":2509},"Tensor accumulation for ",{"type":59,"tag":78,"props":2511,"children":2513},{"className":2512},[],[2514],{"type":64,"value":2515},"stack",{"type":64,"value":396},{"type":59,"tag":78,"props":2518,"children":2520},{"className":2519},[],[2521],{"type":64,"value":2522},"cat",{"type":64,"value":2314},{"type":64,"value":2525}," Type the list with the\nelement shape, then annotate the stack\u002Fcat result with the full shape\nincluding the new dimension (the DSL can't infer collection size from\na dynamic loop).",{"type":59,"tag":60,"props":2527,"children":2528},{},[2529,2530,2535,2536,2542,2544,2550],{"type":64,"value":2264},{"type":59,"tag":70,"props":2531,"children":2532},{},[2533],{"type":64,"value":2534},"Inlined expressions?",{"type":64,"value":1025},{"type":59,"tag":78,"props":2537,"children":2539},{"className":2538},[],[2540],{"type":64,"value":2541},"f(g(x))",{"type":64,"value":2543}," sometimes loses shapes that\n",{"type":59,"tag":78,"props":2545,"children":2547},{"className":2546},[],[2548],{"type":64,"value":2549},"y = g(x); f(y)",{"type":64,"value":2551}," preserves. Break into separate assignments.",{"type":59,"tag":60,"props":2553,"children":2554},{},[2555,2556,2561,2563,2568,2570,2575,2577,2582],{"type":64,"value":2264},{"type":59,"tag":70,"props":2557,"children":2558},{},[2559],{"type":64,"value":2560},"Op genuinely missing from the stubs?",{"type":64,"value":2562}," Confirm it's absent (check the stubs\nand any ",{"type":59,"tag":78,"props":2564,"children":2566},{"className":2565},[],[2567],{"type":64,"value":503},{"type":64,"value":2569}," IR function they reference). A missing shape is\nnot a blocker — it degrades to a bare ",{"type":59,"tag":78,"props":2571,"children":2573},{"className":2572},[],[2574],{"type":64,"value":616},{"type":64,"value":2576}," that you document below. If the\nuser opted into stub changes and a refined signature would recover the shape,\nthat's a fair fix. If instead Pyrefly computes a ",{"type":59,"tag":100,"props":2578,"children":2579},{},[2580],{"type":64,"value":2581},"wrong",{"type":64,"value":2583}," shape, see \"When an\nop's shape is wrong\".",{"type":59,"tag":60,"props":2585,"children":2586},{},[2587,2588,2593,2595,2600],{"type":64,"value":2264},{"type":59,"tag":70,"props":2589,"children":2590},{},[2591],{"type":64,"value":2592},"About to claim an op is untracked?",{"type":64,"value":2594}," Check the shape-aware stubs, their\n",{"type":59,"tag":78,"props":2596,"children":2598},{"className":2597},[],[2599],{"type":64,"value":503},{"type":64,"value":2601}," decorators and IR functions, and special handlers\nfirst. The system tracks reshape, flatten, permute, transpose, cat, stack,\nmatmul, arange, zeros, outer, interpolate, einsum, and many more.",{"type":59,"tag":60,"props":2603,"children":2604},{},[2605,2607,2612],{"type":64,"value":2606},"After EACH restructuring, re-run ",{"type":59,"tag":78,"props":2608,"children":2610},{"className":2609},[],[2611],{"type":64,"value":83},{"type":64,"value":2613}," and update your records.",{"type":59,"tag":60,"props":2615,"children":2616},{},[2617,2622],{"type":59,"tag":70,"props":2618,"children":2619},{},[2620],{"type":64,"value":2621},"STOP before using typed interface.",{"type":64,"value":2623}," For each bare variable where you\nwant typed interface, paste this filled-out receipt in your response:",{"type":59,"tag":533,"props":2625,"children":2628},{"className":2626,"code":2627,"language":64},[536],"## Typed interface receipt [\u003CModule>.\u003Cvar>]: \u003Cvariable> in \u003CClassName.forward>\n- int()\u002Fround() cast: [removed \u002F not applicable — reason]\n- Sequential(*list): [restructured \u002F not applicable — reason]\n- list→tuple: [not applicable — reason]\n- Branch join: [not applicable — reason]\n- Inlined expressions: [split \u002F not applicable — reason]\n- Missing stub\u002FDSL: [checked stubs + `@uses_shape_dsl` IR — reason]\n- Int | None reclassification: [reclassified param X \u002F not applicable — reason]\n- Bridge dim: [promoted X to class Int \u002F not applicable — reason]\n- Config parameterization: [parameterized Config[...] \u002F not applicable — reason]\nResult: still bare after all checks. Using typed interface because ___.\n",[2629],{"type":59,"tag":78,"props":2630,"children":2631},{"__ignoreMap":541},[2632],{"type":64,"value":2627},{"type":59,"tag":60,"props":2634,"children":2635},{},[2636],{"type":64,"value":2637},"If you cannot fill this out, you have not completed Step 4. Go back.",{"type":59,"tag":60,"props":2639,"children":2640},{},[2641,2643,2648,2650,2655],{"type":64,"value":2642},"\"Restructure\" usually means a 2–3 line change: separating an iteration,\nremoving an ",{"type":59,"tag":78,"props":2644,"children":2646},{"className":2645},[],[2647],{"type":64,"value":2273},{"type":64,"value":2649}," cast, or adding an ",{"type":59,"tag":78,"props":2651,"children":2653},{"className":2652},[],[2654],{"type":64,"value":312},{"type":64,"value":2656}," type param. It does NOT mean\nrewriting the algorithm. If you find yourself writing significantly\ndifferent logic, you've gone too far. Even partial dim tracking (e.g.,\noutput dim only) is far more useful than none.",{"type":59,"tag":60,"props":2658,"children":2659},{},[2660,2671,2673,2678],{"type":59,"tag":70,"props":2661,"children":2662},{},[2663,2669],{"type":59,"tag":78,"props":2664,"children":2666},{"className":2665},[],[2667],{"type":64,"value":2668},"type: ignore",{"type":64,"value":2670}," categories.",{"type":64,"value":2672}," Before writing ",{"type":59,"tag":78,"props":2674,"children":2676},{"className":2675},[],[2677],{"type":64,"value":2668},{"type":64,"value":2679},", identify\nwhich category applies:",{"type":59,"tag":108,"props":2681,"children":2682},{},[2683,2706,2730,2746,2776],{"type":59,"tag":112,"props":2684,"children":2685},{},[2686,2691,2692,2698,2700,2705],{"type":59,"tag":70,"props":2687,"children":2688},{},[2689],{"type":64,"value":2690},"A1 algebraic gap",{"type":64,"value":723},{"type":59,"tag":78,"props":2693,"children":2695},{"className":2694},[],[2696],{"type":64,"value":2697},"N * (X \u002F\u002F N) ≠ X",{"type":64,"value":2699},"): no fix, use ",{"type":59,"tag":78,"props":2701,"children":2703},{"className":2702},[],[2704],{"type":64,"value":2668},{"type":64,"value":810},{"type":59,"tag":112,"props":2707,"children":2708},{},[2709,2714,2716,2722,2724,2729],{"type":59,"tag":70,"props":2710,"children":2711},{},[2712],{"type":64,"value":2713},"Conditional equality",{"type":64,"value":2715}," (e.g., ",{"type":59,"tag":78,"props":2717,"children":2719},{"className":2718},[],[2720],{"type":64,"value":2721},"Inp == Oup",{"type":64,"value":2723}," at runtime but separate\ntype params): no fix, use ",{"type":59,"tag":78,"props":2725,"children":2727},{"className":2726},[],[2728],{"type":64,"value":2668},{"type":64,"value":810},{"type":59,"tag":112,"props":2731,"children":2732},{},[2733,2738,2740,2744],{"type":59,"tag":70,"props":2734,"children":2735},{},[2736],{"type":64,"value":2737},"Stub gap",{"type":64,"value":2739}," (op missing, or its signature too loose to track): if the user\nopted into stub changes, refining the stub signature is the fix; otherwise\ndocument the bare result and move on. A ",{"type":59,"tag":100,"props":2741,"children":2742},{},[2743],{"type":64,"value":2581},{"type":64,"value":2745}," computed shape is a different\ncase — see \"When an op's shape is wrong\".",{"type":59,"tag":112,"props":2747,"children":2748},{},[2749,2760,2762,2767,2769,2774],{"type":59,"tag":70,"props":2750,"children":2751},{},[2752,2758],{"type":59,"tag":78,"props":2753,"children":2755},{"className":2754},[],[2756],{"type":64,"value":2757},"return-value",{"type":64,"value":2759}," mismatch from untracked sub-section",{"type":64,"value":2761},": don't\n",{"type":59,"tag":78,"props":2763,"children":2765},{"className":2764},[],[2766],{"type":64,"value":2668},{"type":64,"value":2768},". The fix is upstream — find the bridge dim\nconnecting the untracked section (e.g., ",{"type":59,"tag":78,"props":2770,"children":2772},{"className":2771},[],[2773],{"type":64,"value":1106},{"type":64,"value":2775},"\nfeatures) to the tracked downstream input (e.g., a classifier\nLinear), promote it to a class type param per Step 1's bridge-dim\nrule, then use annotation fallback to recover the shaped return.",{"type":59,"tag":112,"props":2777,"children":2778},{},[2779,2784],{"type":59,"tag":70,"props":2780,"children":2781},{},[2782],{"type":64,"value":2783},"Branch join",{"type":64,"value":2785},": try restructuring first.",{"type":59,"tag":60,"props":2787,"children":2788},{},[2789,2791,2797],{"type":64,"value":2790},"Once you've settled the category, use the specific error code (a bare\n",{"type":59,"tag":78,"props":2792,"children":2794},{"className":2793},[],[2795],{"type":64,"value":2796},"# type: ignore",{"type":64,"value":2798}," is rejected). The codes seen across the corpus:",{"type":59,"tag":108,"props":2800,"children":2801},{},[2802,2828,2839,2864],{"type":59,"tag":112,"props":2803,"children":2804},{},[2805,2811,2813,2818,2820,2826],{"type":59,"tag":78,"props":2806,"children":2808},{"className":2807},[],[2809],{"type":64,"value":2810},"bad-assignment",{"type":64,"value":2812}," — a dataclass field literal default (",{"type":59,"tag":78,"props":2814,"children":2816},{"className":2815},[],[2817],{"type":64,"value":1984},{"type":64,"value":2819},") or\na typed fallback assignment (",{"type":59,"tag":78,"props":2821,"children":2823},{"className":2822},[],[2824],{"type":64,"value":2825},"x: Tensor[[B, N]] = untracked_result",{"type":64,"value":2827},").",{"type":59,"tag":112,"props":2829,"children":2830},{},[2831,2837],{"type":59,"tag":78,"props":2832,"children":2834},{"className":2833},[],[2835],{"type":64,"value":2836},"arg-type",{"type":64,"value":2838}," — passing a bare\u002Flooser value into a shaped parameter (common in\ninit\u002Fsetup helpers).",{"type":59,"tag":112,"props":2840,"children":2841},{},[2842,2848,2849,2855,2857,2862],{"type":59,"tag":78,"props":2843,"children":2845},{"className":2844},[],[2846],{"type":64,"value":2847},"assert-type",{"type":64,"value":314},{"type":59,"tag":78,"props":2850,"children":2852},{"className":2851},[],[2853],{"type":64,"value":2854},"bad-return",{"type":64,"value":2856}," — an A1 algebraic gap where the computed shape\ndiffers from the ",{"type":59,"tag":78,"props":2858,"children":2860},{"className":2859},[],[2861],{"type":64,"value":91},{"type":64,"value":2863},"\u002Fdeclared-return shape.",{"type":59,"tag":112,"props":2865,"children":2866},{},[2867,2873,2874,2879,2881,2886],{"type":59,"tag":78,"props":2868,"children":2870},{"className":2869},[],[2871],{"type":64,"value":2872},"bad-argument-type",{"type":64,"value":556},{"type":59,"tag":78,"props":2875,"children":2877},{"className":2876},[],[2878],{"type":64,"value":2757},{"type":64,"value":2880}," — the argument\u002Freturn variants of the\nabove; ",{"type":59,"tag":78,"props":2882,"children":2884},{"className":2883},[],[2885],{"type":64,"value":2757},{"type":64,"value":2887}," from an untracked sub-section should be fixed upstream\n(see the bridge-dim bullet), not ignored.",{"type":59,"tag":60,"props":2889,"children":2890},{},[2891,2896,2898,2903,2905,2910,2912,2916,2918,2924,2926,2931,2933,2938],{"type":59,"tag":70,"props":2892,"children":2893},{},[2894],{"type":64,"value":2895},"When an op's shape is wrong.",{"type":64,"value":2897}," Everything above handles a ",{"type":59,"tag":100,"props":2899,"children":2900},{},[2901],{"type":64,"value":2902},"missing",{"type":64,"value":2904}," shape (the\nop falls back to bare ",{"type":59,"tag":78,"props":2906,"children":2908},{"className":2907},[],[2909],{"type":64,"value":616},{"type":64,"value":2911},") — that always degrades gracefully and never\nblocks. The rare hard case is a ",{"type":59,"tag":100,"props":2913,"children":2914},{},[2915],{"type":64,"value":2581},{"type":64,"value":2917}," shape: Pyrefly computes a concrete shape\nthat is incorrect (e.g. integer floor-division where the real op rounds up). You\ncannot annotate around this — the checker actively disagrees with reality.\nWhen it happens, tell the user; fixing it means teaching Pyrefly new shape logic,\nnot editing a stub signature. If a shape-DSL skill (e.g. ",{"type":59,"tag":78,"props":2919,"children":2921},{"className":2920},[],[2922],{"type":64,"value":2923},"modify-shaped-array-dsl",{"type":64,"value":2925},")\nis available, hand off to it; otherwise file an upstream issue describing the op\nand the correct rule, and document the spot with ",{"type":59,"tag":78,"props":2927,"children":2929},{"className":2928},[],[2930],{"type":64,"value":2668},{"type":64,"value":2932}," for now. Don't\nreach for this on ordinary bare-",{"type":59,"tag":78,"props":2934,"children":2936},{"className":2935},[],[2937],{"type":64,"value":616},{"type":64,"value":2939}," gaps — only when a computed shape is\nprovably wrong.",{"type":59,"tag":60,"props":2941,"children":2942},{},[2943,2954,2956,2961,2963,2968],{"type":59,"tag":70,"props":2944,"children":2945},{},[2946,2947,2952],{"type":64,"value":2222},{"type":59,"tag":78,"props":2948,"children":2950},{"className":2949},[],[2951],{"type":64,"value":616},{"type":64,"value":2953}," where you know the shape?",{"type":64,"value":2955}," Use ",{"type":59,"tag":78,"props":2957,"children":2959},{"className":2958},[],[2960],{"type":64,"value":91},{"type":64,"value":2962}," to verify\ninference, not annotation fallback. Annotation fallback silently accepts\nbare ",{"type":59,"tag":78,"props":2964,"children":2966},{"className":2965},[],[2967],{"type":64,"value":616},{"type":64,"value":2969}," — it doesn't prove tracking works. If the checker can't\ninfer the shape, trace upstream to find where shapes were actually lost.",{"type":59,"tag":280,"props":2971,"children":2973},{"id":2972},"step-5-write-forward-and-assert_type",[2974],{"type":64,"value":2975},"Step 5: Write forward and assert_type",{"type":59,"tag":60,"props":2977,"children":2978},{},[2979,2984],{"type":59,"tag":70,"props":2980,"children":2981},{},[2982],{"type":64,"value":2983},"Annotation hierarchy",{"type":64,"value":2985}," (most to least desirable):",{"type":59,"tag":145,"props":2987,"children":2988},{},[2989,3002,3020,3033],{"type":59,"tag":112,"props":2990,"children":2991},{},[2992,3000],{"type":59,"tag":70,"props":2993,"children":2994},{},[2995],{"type":59,"tag":78,"props":2996,"children":2998},{"className":2997},[],[2999],{"type":64,"value":91},{"type":64,"value":3001}," — verifies the checker's inference. Proves the system\nworks, not just that you annotated correctly.",{"type":59,"tag":112,"props":3003,"children":3004},{},[3005,3010,3012,3018],{"type":59,"tag":70,"props":3006,"children":3007},{},[3008],{"type":64,"value":3009},"Annotation fallback",{"type":64,"value":3011}," — ",{"type":59,"tag":78,"props":3013,"children":3015},{"className":3014},[],[3016],{"type":64,"value":3017},"x: Tensor[[B, C, H, W]] = unrefined_op(...)",{"type":64,"value":3019},".\nUse when the op returns unrefined but you know the shape. Document WHY.",{"type":59,"tag":112,"props":3021,"children":3022},{},[3023,3031],{"type":59,"tag":70,"props":3024,"children":3025},{},[3026],{"type":59,"tag":78,"props":3027,"children":3029},{"className":3028},[],[3030],{"type":64,"value":2668},{"type":64,"value":3032}," — the checker produces a WRONG type (algebraic gap\nor conditional equality). Last resort. Always include a comment\nexplaining the specific gap.",{"type":59,"tag":112,"props":3034,"children":3035},{},[3036,3045],{"type":59,"tag":70,"props":3037,"children":3038},{},[3039,3040],{"type":64,"value":2222},{"type":59,"tag":78,"props":3041,"children":3043},{"className":3042},[],[3044],{"type":64,"value":616},{"type":64,"value":3046}," — shape genuinely unknowable. Data-dependent token\ncounts, conditional accumulation. Document the specific reason.",{"type":59,"tag":60,"props":3048,"children":3049},{},[3050],{"type":64,"value":3051},"Type the forward signature:",{"type":59,"tag":108,"props":3053,"children":3054},{},[3055,3060,3065],{"type":59,"tag":112,"props":3056,"children":3057},{},[3058],{"type":64,"value":3059},"Class params for fixed dims (set at construction), method params for\nper-call dims (batch size, sequence length, spatial dims).",{"type":59,"tag":112,"props":3061,"children":3062},{},[3063],{"type":64,"value":3064},"Put parameters whose type vars appear in bare (directly bindable)\npositions BEFORE parameters where they appear inside arithmetic\nexpressions. The checker needs to bind the bare params first.",{"type":59,"tag":112,"props":3066,"children":3067},{},[3068,3073,3075,3081,3083,3089,3091,3097,3099,3104,3106,3111,3113,3119],{"type":59,"tag":70,"props":3069,"children":3070},{},[3071],{"type":64,"value":3072},"Don't hide known class dims inside variadic params.",{"type":64,"value":3074}," If the module\nhas a class-level Int ",{"type":59,"tag":78,"props":3076,"children":3078},{"className":3077},[],[3079],{"type":64,"value":3080},"D",{"type":64,"value":3082},", spell the trailing dim out with the variadic\nbatch idiom: ",{"type":59,"tag":78,"props":3084,"children":3086},{"className":3085},[],[3087],{"type":64,"value":3088},"Tensor[[*Elements[Bs], D]]",{"type":64,"value":3090}," (with ",{"type":59,"tag":78,"props":3092,"children":3094},{"className":3093},[],[3095],{"type":64,"value":3096},"Bs: IntTuple",{"type":64,"value":3098},"), not a\nwhole-shape ",{"type":59,"tag":78,"props":3100,"children":3102},{"className":3101},[],[3103],{"type":64,"value":487},{"type":64,"value":3105}," that swallows ",{"type":59,"tag":78,"props":3107,"children":3109},{"className":3108},[],[3110],{"type":64,"value":3080},{"type":64,"value":3112},". See ",{"type":59,"tag":78,"props":3114,"children":3116},{"className":3115},[],[3117],{"type":64,"value":3118},"examples\u002Ftacotron2.py",{"type":64,"value":810},{"type":59,"tag":60,"props":3121,"children":3122},{},[3123,3125,3130,3131,3136],{"type":64,"value":3124},"Replace every ",{"type":59,"tag":78,"props":3126,"children":3128},{"className":3127},[],[3129],{"type":64,"value":83},{"type":64,"value":2378},{"type":59,"tag":78,"props":3132,"children":3134},{"className":3133},[],[3135],{"type":64,"value":91},{"type":64,"value":3137}," using the recorded types:",{"type":59,"tag":108,"props":3139,"children":3140},{},[3141,3160],{"type":59,"tag":112,"props":3142,"children":3143},{},[3144,3146,3151,3152,3158],{"type":64,"value":3145},"Shaped ",{"type":59,"tag":78,"props":3147,"children":3149},{"className":3148},[],[3150],{"type":64,"value":83},{"type":64,"value":731},{"type":59,"tag":78,"props":3153,"children":3155},{"className":3154},[],[3156],{"type":64,"value":3157},"assert_type(x, Tensor[...])",{"type":64,"value":3159}," with that shape.",{"type":59,"tag":112,"props":3161,"children":3162},{},[3163,3164,3169,3170,3176,3178,3184],{"type":64,"value":2222},{"type":59,"tag":78,"props":3165,"children":3167},{"className":3166},[],[3168],{"type":64,"value":83},{"type":64,"value":731},{"type":59,"tag":78,"props":3171,"children":3173},{"className":3172},[],[3174],{"type":64,"value":3175},"assert_type(x, Tensor)",{"type":64,"value":3177}," to document the tracking\ngap, plus a comment noting the root cause (e.g., ",{"type":59,"tag":78,"props":3179,"children":3181},{"className":3180},[],[3182],{"type":64,"value":3183},"# Sequential(*list)",{"type":64,"value":2827},{"type":59,"tag":60,"props":3186,"children":3187},{},[3188,3199,3201,3206,3208,3213,3215,3220],{"type":59,"tag":70,"props":3189,"children":3190},{},[3191,3193,3198],{"type":64,"value":3192},"Every local variable in every forward method gets an ",{"type":59,"tag":78,"props":3194,"children":3196},{"className":3195},[],[3197],{"type":64,"value":91},{"type":64,"value":810},{"type":64,"value":3200},"\nNo exceptions — even inside typed-interface modules. Typed interface means\nthe ",{"type":59,"tag":100,"props":3202,"children":3203},{},[3204],{"type":64,"value":3205},"boundary",{"type":64,"value":3207}," is typed — it does NOT mean internals are exempt from\n",{"type":59,"tag":78,"props":3209,"children":3211},{"className":3210},[],[3212],{"type":64,"value":91},{"type":64,"value":3214},". If you think a shape expression is \"too complex to write,\"\nyou are guessing — look at what ",{"type":59,"tag":78,"props":3216,"children":3218},{"className":3217},[],[3219],{"type":64,"value":83},{"type":64,"value":3221}," showed you. The checker\nsimplifies aggressively.",{"type":59,"tag":60,"props":3223,"children":3224},{},[3225,3227,3232],{"type":64,"value":3226},"Run the checker. Fix any ",{"type":59,"tag":78,"props":3228,"children":3230},{"className":3229},[],[3231],{"type":64,"value":91},{"type":64,"value":3233}," failures.",{"type":59,"tag":60,"props":3235,"children":3236},{},[3237,3242],{"type":59,"tag":70,"props":3238,"children":3239},{},[3240],{"type":64,"value":3241},"VERIFY before leaving Step 5.",{"type":64,"value":3243}," Paste this in your response:",{"type":59,"tag":533,"props":3245,"children":3248},{"className":3246,"code":3247,"language":64},[536],"# assert_type count for ClassName.forward:\n# Locals: var1, var2, var3 (N total)\n# assert_type calls: N\n# Match: yes\n",[3249],{"type":59,"tag":78,"props":3250,"children":3251},{"__ignoreMap":541},[3252],{"type":64,"value":3247},{"type":59,"tag":60,"props":3254,"children":3255},{},[3256],{"type":64,"value":3257},"If the counts don't match, you missed some. Go back and add them.",{"type":59,"tag":60,"props":3259,"children":3260},{},[3261,3266,3268,3273,3275,3281],{"type":59,"tag":70,"props":3262,"children":3263},{},[3264],{"type":64,"value":3265},"Step 4 receipt check.",{"type":64,"value":3267}," Every bare ",{"type":59,"tag":78,"props":3269,"children":3271},{"className":3270},[],[3272],{"type":64,"value":3175},{"type":64,"value":3274}," and\nevery annotation fallback (",{"type":59,"tag":78,"props":3276,"children":3278},{"className":3277},[],[3279],{"type":64,"value":3280},"x: Tensor[[B, C]] = untracked_op(...)",{"type":64,"value":3282},")\nmust cite the Step 4 receipt that justifies it. If no receipt exists,\ngo back to Step 4 — the restructuring attempt was skipped.",{"type":59,"tag":533,"props":3284,"children":3287},{"className":3285,"code":3286,"language":64},[536],"# Bare\u002Ffallback assert_types and their Step 4 receipts:\n# - var2 (bare): receipt MLP.var2 — Sequential(*list), not restructurable\n# - var3 (fallback): receipt MLP.var3 — stub returns unrefined, shape known from context\n# - var5 (bare): receipt MLP.var5 — input is bare (upstream contagion)\n",[3288],{"type":59,"tag":78,"props":3289,"children":3290},{"__ignoreMap":541},[3291],{"type":64,"value":3286},{"type":59,"tag":60,"props":3293,"children":3294},{},[3295,3300,3302,3307,3309,3315],{"type":59,"tag":70,"props":3296,"children":3297},{},[3298],{"type":64,"value":3299},"Smoke tests at the bottom of the file",{"type":64,"value":3301}," must use ",{"type":59,"tag":78,"props":3303,"children":3305},{"className":3304},[],[3306],{"type":64,"value":91},{"type":64,"value":3308}," on\nthe typed output, not ",{"type":59,"tag":78,"props":3310,"children":3312},{"className":3311},[],[3313],{"type":64,"value":3314},"assert out.shape == (...)",{"type":64,"value":3316},". Runtime shape\nasserts don't exercise pyrefly — they only prove the model runs.\nExample:",{"type":59,"tag":533,"props":3318,"children":3320},{"className":639,"code":3319,"language":25,"meta":541,"style":541},"model = MyModel(num_classes=10)\nx = torch.randn(2, 3, 32, 32)  # inferred as Tensor[[2, 3, 32, 32]]\nout = model(x)\nassert_type(out, Tensor[[2, 10]])  # not: assert out.shape == (2, 10)\n",[3321],{"type":59,"tag":78,"props":3322,"children":3323},{"__ignoreMap":541},[3324,3332,3340,3348],{"type":59,"tag":646,"props":3325,"children":3326},{"class":648,"line":649},[3327],{"type":59,"tag":646,"props":3328,"children":3329},{},[3330],{"type":64,"value":3331},"model = MyModel(num_classes=10)\n",{"type":59,"tag":646,"props":3333,"children":3334},{"class":648,"line":658},[3335],{"type":59,"tag":646,"props":3336,"children":3337},{},[3338],{"type":64,"value":3339},"x = torch.randn(2, 3, 32, 32)  # inferred as Tensor[[2, 3, 32, 32]]\n",{"type":59,"tag":646,"props":3341,"children":3342},{"class":648,"line":667},[3343],{"type":59,"tag":646,"props":3344,"children":3345},{},[3346],{"type":64,"value":3347},"out = model(x)\n",{"type":59,"tag":646,"props":3349,"children":3350},{"class":648,"line":676},[3351],{"type":59,"tag":646,"props":3352,"children":3353},{},[3354],{"type":64,"value":3355},"assert_type(out, Tensor[[2, 10]])  # not: assert out.shape == (2, 10)\n",{"type":59,"tag":280,"props":3357,"children":3359},{"id":3358},"step-6-post-module-checklist",[3360],{"type":64,"value":3361},"Step 6: Post-module checklist",{"type":59,"tag":60,"props":3363,"children":3364},{},[3365,3367,3372],{"type":64,"value":3366},"Copy this template into your response and fill ",{"type":59,"tag":70,"props":3368,"children":3369},{},[3370],{"type":64,"value":3371},"every line",{"type":64,"value":3373}," before\nproceeding to the next module.",{"type":59,"tag":533,"props":3375,"children":3378},{"className":3376,"code":3377,"language":64},[536],"### Post-module: \u003CClassName>\n- type: ignore count: ___\n  For each: [line] [category: A1 \u002F conditional \u002F stub-gap] [fix attempted]\n- Step 4 receipts: [list receipt IDs, or \"none — all locals shaped\"]\n- int params: [list each int param and why it's not Int, or \"none\"]\n- int() casts: [list each, or \"none\"]\n- Sequential(*list): [list each instance and what you did, or \"none\"]\n- bare Tensor in sigs: [list each with reason, or \"none\"]\n- assert_type: ___ checkpoints covering ___ locals in ___ forward methods\n- missing stubs: [list each, or \"none\"]\n",[3379],{"type":59,"tag":78,"props":3380,"children":3381},{"__ignoreMap":541},[3382],{"type":64,"value":3377},{"type":59,"tag":60,"props":3384,"children":3385},{},[3386],{"type":64,"value":3387},"Do not proceed to the next module with unfilled lines.",{"type":59,"tag":133,"props":3389,"children":3391},{"id":3390},"verification-draft-review",[3392],{"type":64,"value":3393},"Verification (draft review)",{"type":59,"tag":60,"props":3395,"children":3396},{},[3397],{"type":64,"value":3398},"Everything above produced a DRAFT. This phase reviews it.",{"type":59,"tag":280,"props":3400,"children":3402},{"id":3401},"run-verify_portsh",[3403],{"type":64,"value":3404},"Run verify_port.sh",{"type":59,"tag":60,"props":3406,"children":3407},{},[3408,3410,3416],{"type":64,"value":3409},"Run ",{"type":59,"tag":78,"props":3411,"children":3413},{"className":3412},[],[3414],{"type":64,"value":3415},"verify_port.sh",{"type":64,"value":3417}," (in this skill dir) on your port file:",{"type":59,"tag":533,"props":3419,"children":3423},{"className":3420,"code":3421,"language":3422,"meta":541,"style":541},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","tensor-shapes\u002Fskills\u002Fadd-shape-types-to-torch-model\u002Fverify_port.sh \u003Cpath\u002Fto\u002Fyour\u002Fport.py>\n","bash",[3424],{"type":59,"tag":78,"props":3425,"children":3426},{"__ignoreMap":541},[3427],{"type":59,"tag":646,"props":3428,"children":3429},{"class":648,"line":649},[3430,3436,3442,3448,3454],{"type":59,"tag":646,"props":3431,"children":3433},{"style":3432},"--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B",[3434],{"type":64,"value":3435},"tensor-shapes\u002Fskills\u002Fadd-shape-types-to-torch-model\u002Fverify_port.sh",{"type":59,"tag":646,"props":3437,"children":3439},{"style":3438},"--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF",[3440],{"type":64,"value":3441}," \u003C",{"type":59,"tag":646,"props":3443,"children":3445},{"style":3444},"--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D",[3446],{"type":64,"value":3447},"path\u002Fto\u002Fyour\u002Fport.p",{"type":59,"tag":646,"props":3449,"children":3451},{"style":3450},"--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8",[3452],{"type":64,"value":3453},"y",{"type":59,"tag":646,"props":3455,"children":3456},{"style":3438},[3457],{"type":64,"value":3458},">\n",{"type":59,"tag":60,"props":3460,"children":3461},{},[3462,3467],{"type":59,"tag":70,"props":3463,"children":3464},{},[3465],{"type":64,"value":3466},"Paste the FULL output",{"type":64,"value":3468}," in your response. Do not summarize or\nparaphrase — the raw output is the artifact.",{"type":59,"tag":280,"props":3470,"children":3472},{"id":3471},"run-the-actual-pyrefly-check",[3473],{"type":64,"value":3474},"Run the actual Pyrefly check",{"type":59,"tag":60,"props":3476,"children":3477},{},[3478,3483,3485,3491,3493,3498,3500,3506],{"type":59,"tag":78,"props":3479,"children":3481},{"className":3480},[],[3482],{"type":64,"value":3415},{"type":64,"value":3484}," is a heuristic quality gate; it does not type check the port.\nYou must also run Pyrefly itself against your port file. There is no\n",{"type":59,"tag":78,"props":3486,"children":3488},{"className":3487},[],[3489],{"type":64,"value":3490},"--tensor-shapes",{"type":64,"value":3492}," flag — shape tracking is on whenever the shape stubs and\n",{"type":59,"tag":78,"props":3494,"children":3496},{"className":3495},[],[3497],{"type":64,"value":304},{"type":64,"value":3499}," are on the search path. The single-file check mirrors\n",{"type":59,"tag":78,"props":3501,"children":3503},{"className":3502},[],[3504],{"type":64,"value":3505},"tensor-shapes\u002Fpyrefly-torch-stubs\u002Frun_pyrefly.py",{"type":64,"value":106},{"type":59,"tag":533,"props":3508,"children":3510},{"className":3420,"code":3509,"language":3422,"meta":541,"style":541},"pyrefly check --config \u002Fdev\u002Fnull --python-version 3.13 \\\n    --search-path \u003Croot containing torch-stubs> \\\n    --search-path \u003Croot containing shape_extensions> \\\n    path\u002Fto\u002Fyour\u002Fport.py\n",[3511],{"type":59,"tag":78,"props":3512,"children":3513},{"__ignoreMap":541},[3514,3552,3592,3628],{"type":59,"tag":646,"props":3515,"children":3516},{"class":648,"line":649},[3517,3521,3526,3531,3536,3541,3547],{"type":59,"tag":646,"props":3518,"children":3519},{"style":3432},[3520],{"type":64,"value":187},{"type":59,"tag":646,"props":3522,"children":3523},{"style":3444},[3524],{"type":64,"value":3525}," check",{"type":59,"tag":646,"props":3527,"children":3528},{"style":3444},[3529],{"type":64,"value":3530}," --config",{"type":59,"tag":646,"props":3532,"children":3533},{"style":3444},[3534],{"type":64,"value":3535}," \u002Fdev\u002Fnull",{"type":59,"tag":646,"props":3537,"children":3538},{"style":3444},[3539],{"type":64,"value":3540}," --python-version",{"type":59,"tag":646,"props":3542,"children":3544},{"style":3543},"--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C",[3545],{"type":64,"value":3546}," 3.13",{"type":59,"tag":646,"props":3548,"children":3549},{"style":3450},[3550],{"type":64,"value":3551}," \\\n",{"type":59,"tag":646,"props":3553,"children":3554},{"class":648,"line":658},[3555,3560,3564,3568,3573,3578,3583,3588],{"type":59,"tag":646,"props":3556,"children":3557},{"style":3444},[3558],{"type":64,"value":3559},"    --search-path",{"type":59,"tag":646,"props":3561,"children":3562},{"style":3438},[3563],{"type":64,"value":3441},{"type":59,"tag":646,"props":3565,"children":3566},{"style":3444},[3567],{"type":64,"value":56},{"type":59,"tag":646,"props":3569,"children":3570},{"style":3444},[3571],{"type":64,"value":3572}," containing",{"type":59,"tag":646,"props":3574,"children":3575},{"style":3444},[3576],{"type":64,"value":3577}," torch-stub",{"type":59,"tag":646,"props":3579,"children":3580},{"style":3450},[3581],{"type":64,"value":3582},"s",{"type":59,"tag":646,"props":3584,"children":3585},{"style":3438},[3586],{"type":64,"value":3587},">",{"type":59,"tag":646,"props":3589,"children":3590},{"style":3450},[3591],{"type":64,"value":3551},{"type":59,"tag":646,"props":3593,"children":3594},{"class":648,"line":667},[3595,3599,3603,3607,3611,3616,3620,3624],{"type":59,"tag":646,"props":3596,"children":3597},{"style":3444},[3598],{"type":64,"value":3559},{"type":59,"tag":646,"props":3600,"children":3601},{"style":3438},[3602],{"type":64,"value":3441},{"type":59,"tag":646,"props":3604,"children":3605},{"style":3444},[3606],{"type":64,"value":56},{"type":59,"tag":646,"props":3608,"children":3609},{"style":3444},[3610],{"type":64,"value":3572},{"type":59,"tag":646,"props":3612,"children":3613},{"style":3444},[3614],{"type":64,"value":3615}," shape_extension",{"type":59,"tag":646,"props":3617,"children":3618},{"style":3450},[3619],{"type":64,"value":3582},{"type":59,"tag":646,"props":3621,"children":3622},{"style":3438},[3623],{"type":64,"value":3587},{"type":59,"tag":646,"props":3625,"children":3626},{"style":3450},[3627],{"type":64,"value":3551},{"type":59,"tag":646,"props":3629,"children":3630},{"class":648,"line":676},[3631],{"type":59,"tag":646,"props":3632,"children":3633},{"style":3444},[3634],{"type":64,"value":3635},"    path\u002Fto\u002Fyour\u002Fport.py\n",{"type":59,"tag":60,"props":3637,"children":3638},{},[3639,3641,3647,3649,3655,3657,3663,3664,3669,3671,3677,3679,3685,3687,3692],{"type":64,"value":3640},"The two search roots are separate: ",{"type":59,"tag":78,"props":3642,"children":3644},{"className":3643},[],[3645],{"type":64,"value":3646},"tensor-shapes\u002Fpyrefly-torch-stubs",{"type":64,"value":3648}," (the\n",{"type":59,"tag":78,"props":3650,"children":3652},{"className":3651},[],[3653],{"type":64,"value":3654},"torch-stubs",{"type":64,"value":3656}," package) and ",{"type":59,"tag":78,"props":3658,"children":3660},{"className":3659},[],[3661],{"type":64,"value":3662},"tensor-shapes\u002Fpyrefly-shape-extensions",{"type":64,"value":3648},{"type":59,"tag":78,"props":3665,"children":3667},{"className":3666},[],[3668],{"type":64,"value":304},{"type":64,"value":3670}," package). In a Buck checkout you can instead pass the combined\nfilegroup ",{"type":59,"tag":78,"props":3672,"children":3674},{"className":3673},[],[3675],{"type":64,"value":3676},"fbcode\u002F\u002Fpyrefly\u002Ftensor-shapes:torch-stubs-search-path",{"type":64,"value":3678}," as a\n",{"type":59,"tag":78,"props":3680,"children":3682},{"className":3681},[],[3683],{"type":64,"value":3684},"--search-path",{"type":64,"value":3686},". If a skill invoked this one, it may supply its own\nbuild-and-check command; use that instead. ",{"type":59,"tag":78,"props":3688,"children":3690},{"className":3689},[],[3691],{"type":64,"value":203},{"type":64,"value":3693}," reports the\nresolved search path when the stubs are already installed in your environment.",{"type":59,"tag":60,"props":3695,"children":3696},{},[3697,3702,3704,3710,3712,3718,3720,3726],{"type":59,"tag":70,"props":3698,"children":3699},{},[3700],{"type":64,"value":3701},"Python version:",{"type":64,"value":3703}," the PEP 695\u002F696 generics syntax (",{"type":59,"tag":78,"props":3705,"children":3707},{"className":3706},[],[3708],{"type":64,"value":3709},"class Net[D: IntVar]",{"type":64,"value":3711},",\ntype-param defaults) requires ",{"type":59,"tag":78,"props":3713,"children":3715},{"className":3714},[],[3716],{"type":64,"value":3717},"--python-version 3.12",{"type":64,"value":3719}," or later; the corpus runs\n",{"type":59,"tag":78,"props":3721,"children":3723},{"className":3722},[],[3724],{"type":64,"value":3725},"3.13",{"type":64,"value":810},{"type":59,"tag":60,"props":3728,"children":3729},{},[3730],{"type":64,"value":3731},"To type-check the whole corpus (or a stack of edits) at once:",{"type":59,"tag":533,"props":3733,"children":3735},{"className":3420,"code":3734,"language":3422,"meta":541,"style":541},"python3 tensor-shapes\u002Frun_all_shape_tests.py --mode cargo|buck [--include-runtime-tests]\n",[3736],{"type":59,"tag":78,"props":3737,"children":3738},{"__ignoreMap":541},[3739],{"type":59,"tag":646,"props":3740,"children":3741},{"class":648,"line":649},[3742,3747,3752,3757,3762,3767,3772],{"type":59,"tag":646,"props":3743,"children":3744},{"style":3432},[3745],{"type":64,"value":3746},"python3",{"type":59,"tag":646,"props":3748,"children":3749},{"style":3444},[3750],{"type":64,"value":3751}," tensor-shapes\u002Frun_all_shape_tests.py",{"type":59,"tag":646,"props":3753,"children":3754},{"style":3444},[3755],{"type":64,"value":3756}," --mode",{"type":59,"tag":646,"props":3758,"children":3759},{"style":3444},[3760],{"type":64,"value":3761}," cargo",{"type":59,"tag":646,"props":3763,"children":3764},{"style":3438},[3765],{"type":64,"value":3766},"|",{"type":59,"tag":646,"props":3768,"children":3769},{"style":3432},[3770],{"type":64,"value":3771},"buck",{"type":59,"tag":646,"props":3773,"children":3774},{"style":3450},[3775],{"type":64,"value":3776}," [--include-runtime-tests]\n",{"type":59,"tag":60,"props":3778,"children":3779},{},[3780,3782,3788,3790,3795],{"type":64,"value":3781},"Paste the Pyrefly output. The result must be ",{"type":59,"tag":78,"props":3783,"children":3785},{"className":3784},[],[3786],{"type":64,"value":3787},"0 errors",{"type":64,"value":3789},"; ",{"type":59,"tag":78,"props":3791,"children":3793},{"className":3792},[],[3794],{"type":64,"value":83},{"type":64,"value":3796}," info is\nacceptable only while probing and must not remain in the finished port.",{"type":59,"tag":280,"props":3798,"children":3800},{"id":3799},"investigate-each-warning",[3801],{"type":64,"value":3802},"Investigate each warning",{"type":59,"tag":60,"props":3804,"children":3805},{},[3806],{"type":64,"value":3807},"For EACH warning in the verify_port.sh output, write one of:",{"type":59,"tag":108,"props":3809,"children":3810},{},[3811,3821],{"type":59,"tag":112,"props":3812,"children":3813},{},[3814,3819],{"type":59,"tag":70,"props":3815,"children":3816},{},[3817],{"type":64,"value":3818},"Fixed",{"type":64,"value":3820},": what you changed and why.",{"type":59,"tag":112,"props":3822,"children":3823},{},[3824,3829],{"type":59,"tag":70,"props":3825,"children":3826},{},[3827],{"type":64,"value":3828},"Accepted",{"type":64,"value":3830},": why this warning is not actionable (cite the specific\ncategory — A1 algebraic, conditional equality, stub gap not worth\nfixing, etc.).",{"type":59,"tag":60,"props":3832,"children":3833},{},[3834],{"type":64,"value":3835},"Do not write \"all warnings audited\" — list them individually.",{"type":59,"tag":280,"props":3837,"children":3839},{"id":3838},"audit-bare-assert_types",[3840],{"type":64,"value":3841},"Audit bare assert_types",{"type":59,"tag":60,"props":3843,"children":3844},{},[3845,3847,3852,3854,3859,3861,3866],{"type":64,"value":3846},"The port's quality metric is: what fraction of ",{"type":59,"tag":78,"props":3848,"children":3850},{"className":3849},[],[3851],{"type":64,"value":91},{"type":64,"value":3853}," calls verify\na shaped type vs. document a bare ",{"type":59,"tag":78,"props":3855,"children":3857},{"className":3856},[],[3858],{"type":64,"value":616},{"type":64,"value":3860}," gap? Every bare\n",{"type":59,"tag":78,"props":3862,"children":3864},{"className":3863},[],[3865],{"type":64,"value":3175},{"type":64,"value":3867}," is a tracking gap. Minimizing these is the goal.",{"type":59,"tag":60,"props":3869,"children":3870},{},[3871,3873,3878],{"type":64,"value":3872},"For each ",{"type":59,"tag":78,"props":3874,"children":3876},{"className":3875},[],[3877],{"type":64,"value":3175},{"type":64,"value":3879}," in the port (bare, no shape params):",{"type":59,"tag":145,"props":3881,"children":3882},{},[3883,3901],{"type":59,"tag":112,"props":3884,"children":3885},{},[3886,3888,3893,3894,3900],{"type":64,"value":3887},"It MUST have a comment explaining the root cause (e.g.,\n",{"type":59,"tag":78,"props":3889,"children":3891},{"className":3890},[],[3892],{"type":64,"value":3183},{"type":64,"value":556},{"type":59,"tag":78,"props":3895,"children":3897},{"className":3896},[],[3898],{"type":64,"value":3899},"# input is bare",{"type":64,"value":2827},{"type":59,"tag":112,"props":3902,"children":3903},{},[3904],{"type":64,"value":3905},"The root cause MUST have a typed interface receipt from Step 4\n(or trace to one — e.g., \"input is bare\" because the caller's\nSequential(*list) was documented in the parent module's receipt).",{"type":59,"tag":60,"props":3907,"children":3908},{},[3909,3911,3916],{"type":64,"value":3910},"If any bare ",{"type":59,"tag":78,"props":3912,"children":3914},{"className":3913},[],[3915],{"type":64,"value":91},{"type":64,"value":3917}," lacks a comment or receipt trail, go back\nand either fix the tracking gap or document it properly.",{"type":59,"tag":60,"props":3919,"children":3920},{},[3921],{"type":59,"tag":70,"props":3922,"children":3923},{},[3924],{"type":64,"value":3925},"Paste the bare audit in your response:",{"type":59,"tag":533,"props":3927,"children":3930},{"className":3928,"code":3929,"language":64},[536],"## Bare assert_type audit\nTotal assert_type in forward bodies: ___\nShaped (assert_type(x, Tensor[...])): ___\nBare (assert_type(x, Tensor)): ___\nBare fraction: ___\n\nEach bare:\n- line N: var — root cause (receipt: \u003Cmodule>.Step4)\n- line M: var — root cause (receipt: \u003Cmodule>.Step4)\n",[3931],{"type":59,"tag":78,"props":3932,"children":3933},{"__ignoreMap":541},[3934],{"type":64,"value":3929},{"type":59,"tag":280,"props":3936,"children":3938},{"id":3937},"compare-against-known-patterns",[3939],{"type":64,"value":3940},"Compare against known patterns",{"type":59,"tag":60,"props":3942,"children":3943},{},[3944,3955],{"type":59,"tag":70,"props":3945,"children":3946},{},[3947,3948,3953],{"type":64,"value":290},{"type":59,"tag":78,"props":3949,"children":3951},{"className":3950},[],[3952],{"type":64,"value":365},{"type":64,"value":3954}," NOW — not earlier.",{"type":64,"value":3956}," It is comparison material\nfor your draft, not preparation material. Reading it during pre-flight\nbiases you toward patterns you haven't empirically verified.",{"type":59,"tag":60,"props":3958,"children":3959},{},[3960,3962],{"type":64,"value":3961},"For each module in your port, find the closest matching pattern in the\nstyle guide. ",{"type":59,"tag":70,"props":3963,"children":3964},{},[3965],{"type":64,"value":3966},"Paste a comparison:",{"type":59,"tag":533,"props":3968,"children":3971},{"className":3969,"code":3970,"language":64},[536],"## Style guide comparison\n| Module | My approach | Closest style guide pattern | Could I improve? |\n|--------|------------|---------------------------|-----------------|\n| ... | ... | ... | yes\u002Fno — reason |\n",[3972],{"type":59,"tag":78,"props":3973,"children":3974},{"__ignoreMap":541},[3975],{"type":64,"value":3970},{"type":59,"tag":60,"props":3977,"children":3978},{},[3979],{"type":64,"value":3980},"If any row says \"yes\", go back and try the improvement before proceeding.\nIf it doesn't work, document why in the row.",{"type":59,"tag":280,"props":3982,"children":3984},{"id":3983},"re-run-verify_portsh",[3985],{"type":64,"value":3986},"Re-run verify_port.sh",{"type":59,"tag":60,"props":3988,"children":3989},{},[3990],{"type":64,"value":3991},"If you made any changes during this phase, re-run the script and paste\nthe new output. If no changes were made, write \"No changes — output\nunchanged.\"",{"type":59,"tag":60,"props":3993,"children":3994},{},[3995,4000,4002,4007,4009,4014],{"type":59,"tag":70,"props":3996,"children":3997},{},[3998],{"type":64,"value":3999},"Re-check callers.",{"type":64,"value":4001}," If you changed a module's forward signature or\nreturn type during this phase, re-run ",{"type":59,"tag":78,"props":4003,"children":4005},{"className":4004},[],[4006],{"type":64,"value":83},{"type":64,"value":4008}," in every module\nthat calls it and update their ",{"type":59,"tag":78,"props":4010,"children":4012},{"className":4011},[],[4013],{"type":64,"value":91},{"type":64,"value":4015}," expectations. A fix to\nmodule X can change the inferred types in module Y's forward body.",{"type":59,"tag":280,"props":4017,"children":4019},{"id":4018},"completion-report",[4020],{"type":64,"value":4021},"Completion report",{"type":59,"tag":60,"props":4023,"children":4024},{},[4025,4027],{"type":64,"value":4026},"Before reporting the port as done, copy and fill this template in your\nresponse. ",{"type":59,"tag":70,"props":4028,"children":4029},{},[4030],{"type":64,"value":4031},"Do not report completion with unfilled blanks.",{"type":59,"tag":533,"props":4033,"children":4036},{"className":4034,"code":4035,"language":64},[536],"## Port complete: \u003Cmodel name>\nGate 1 ops audited: ___. Stubs added\u002Ffixed: ___.\nGate 2 inventory items: ___. All checked off: yes\u002Fno.\nModules ported (dependency order): ___\nStep 6 checklists filled for each: yes\u002Fno\ntype: ignore total: ___\n  ___ A1 algebraic, ___ conditional equality, ___ stub gap, ___ other\nassert_type total: ___ (___ shaped, ___ bare)\nBare fraction: ___%\nEach bare assert_type has comment + receipt trail: yes\u002Fno\nsmoke tests: ___ — all use `assert_type` on typed output (not `.shape ==`): yes\u002Fno\n\nVerification phase:\n- verify_port.sh warnings: ___\n  Fixed: ___. Accepted: ___ (each justified above).\n- Pyrefly check: 0 errors: yes\u002Fno\n- Style guide comparison rows: ___\n  Improvements attempted: ___. Improvements that worked: ___.\n- verify_port.sh re-run (if changes made): 0 actionable: yes\u002Fno\n\nGaps & proposed improvements (for the user):\n- Ops that stayed untracked, and why: ___ (or \"none\")\n- Stub-signature improvements that would recover shapes (if stubs weren't\n  changed): ___ (or \"none\")\n- Wrong computed shapes found (needing a shape-DSL change): ___ (or \"none\")\n- Suggest filing an upstream issue for: ___ (or \"none\")\n",[4037],{"type":59,"tag":78,"props":4038,"children":4039},{"__ignoreMap":541},[4040],{"type":64,"value":4035},{"type":59,"tag":60,"props":4042,"children":4043},{},[4044,4046,4051],{"type":64,"value":4045},"The \"Gaps & proposed improvements\" block is the user-facing payload of the\nlighter deliverable — when you didn't paste the full tables, this is where the\nshortcomings of the port surface. Fill it from the ",{"type":59,"tag":78,"props":4047,"children":4049},{"className":4048},[],[4050],{"type":64,"value":577},{"type":64,"value":4052},"s you recorded in Gate 1\nand the Step 4 receipts.",{"type":59,"tag":133,"props":4054,"children":4056},{"id":4055},"import-convention",[4057],{"type":64,"value":4058},"Import convention",{"type":59,"tag":60,"props":4060,"children":4061},{},[4062,4063,4068,4070,4076,4077,4082,4084,4090,4092,4097,4099,4105,4106,4112,4114,4120,4122,4128,4130,4135],{"type":64,"value":1954},{"type":59,"tag":78,"props":4064,"children":4066},{"className":4065},[],[4067],{"type":64,"value":304},{"type":64,"value":4069}," package bridges pyrefly's type system and Python runtime.\nImporting it patches ",{"type":59,"tag":78,"props":4071,"children":4073},{"className":4072},[],[4074],{"type":64,"value":4075},"torch.Tensor",{"type":64,"value":556},{"type":59,"tag":78,"props":4078,"children":4080},{"className":4079},[],[4081],{"type":64,"value":847},{"type":64,"value":4083},", and other torch classes to\naccept subscript syntax (e.g., ",{"type":59,"tag":78,"props":4085,"children":4087},{"className":4086},[],[4088],{"type":64,"value":4089},"Tensor[[B, C, H, W]]",{"type":64,"value":4091},") at runtime without\ncrashing. It also provides ",{"type":59,"tag":78,"props":4093,"children":4095},{"className":4094},[],[4096],{"type":64,"value":320},{"type":64,"value":4098}," with arithmetic support (",{"type":59,"tag":78,"props":4100,"children":4102},{"className":4101},[],[4103],{"type":64,"value":4104},"N + 1",{"type":64,"value":556},{"type":59,"tag":78,"props":4107,"children":4109},{"className":4108},[],[4110],{"type":64,"value":4111},"N \u002F\u002F 2",{"type":64,"value":4113},"\nreturn ",{"type":59,"tag":78,"props":4115,"children":4117},{"className":4116},[],[4118],{"type":64,"value":4119},"self",{"type":64,"value":4121}," instead of ",{"type":59,"tag":78,"props":4123,"children":4125},{"className":4124},[],[4126],{"type":64,"value":4127},"TypeError",{"type":64,"value":4129},") and ",{"type":59,"tag":78,"props":4131,"children":4133},{"className":4132},[],[4134],{"type":64,"value":312},{"type":64,"value":4136}," for binding runtime ints to\ntype-level symbols.",{"type":59,"tag":60,"props":4138,"children":4139},{},[4140,4145,4147,4152,4154,4160,4162,4168,4170,4175,4177,4182],{"type":59,"tag":78,"props":4141,"children":4143},{"className":4142},[],[4144],{"type":64,"value":304},{"type":64,"value":4146}," is installed alongside the shape-aware torch stubs (wherever\nthose live in your environment — ",{"type":59,"tag":78,"props":4148,"children":4150},{"className":4149},[],[4151],{"type":64,"value":203},{"type":64,"value":4153}," reports the location). In an\nfbsource Buck checkout specifically, the runtime package is\n",{"type":59,"tag":78,"props":4155,"children":4157},{"className":4156},[],[4158],{"type":64,"value":4159},"fbcode\u002F\u002Fpyrefly\u002Ftensor-shapes\u002Fpyrefly-shape-extensions:shape_extensions",{"type":64,"value":4161},", the importable stub package is\n",{"type":59,"tag":78,"props":4163,"children":4165},{"className":4164},[],[4166],{"type":64,"value":4167},"fbcode\u002F\u002Fpyrefly\u002Ftensor-shapes\u002Fpyrefly-torch-stubs:torch-stubs",{"type":64,"value":4169},", and the\nfilegroup to pass as a Pyrefly ",{"type":59,"tag":78,"props":4171,"children":4173},{"className":4172},[],[4174],{"type":64,"value":3684},{"type":64,"value":4176}," is\n",{"type":59,"tag":78,"props":4178,"children":4180},{"className":4179},[],[4181],{"type":64,"value":3676},{"type":64,"value":810},{"type":59,"tag":60,"props":4184,"children":4185},{},[4186,4188,4193],{"type":64,"value":4187},"Pick an import mode based on whether the port file will be ",{"type":59,"tag":70,"props":4189,"children":4190},{},[4191],{"type":64,"value":4192},"executed",{"type":64,"value":4194},", not\njust type-checked:",{"type":59,"tag":60,"props":4196,"children":4197},{},[4198,4203],{"type":59,"tag":100,"props":4199,"children":4200},{},[4201],{"type":64,"value":4202},"Static-check-only (common case — you only run the checker on the file):",{"type":64,"value":4204}," guard\nthe shape imports. The file is never executed, so the annotations never evaluate\nand the guarded names need not resolve at runtime.",{"type":59,"tag":533,"props":4206,"children":4208},{"className":639,"code":4207,"language":25,"meta":541,"style":541},"from typing import assert_type, TYPE_CHECKING\n\nimport torch\nimport torch.nn as nn\n\nif TYPE_CHECKING:\n    from torch import Tensor\n    from shape_extensions import Elements, Int, IntTuple, IntVar\n",[4209],{"type":59,"tag":78,"props":4210,"children":4211},{"__ignoreMap":541},[4212,4220,4227,4235,4243,4250,4258,4266],{"type":59,"tag":646,"props":4213,"children":4214},{"class":648,"line":649},[4215],{"type":59,"tag":646,"props":4216,"children":4217},{},[4218],{"type":64,"value":4219},"from typing import assert_type, TYPE_CHECKING\n",{"type":59,"tag":646,"props":4221,"children":4222},{"class":648,"line":658},[4223],{"type":59,"tag":646,"props":4224,"children":4225},{"emptyLinePlaceholder":1431},[4226],{"type":64,"value":1434},{"type":59,"tag":646,"props":4228,"children":4229},{"class":648,"line":667},[4230],{"type":59,"tag":646,"props":4231,"children":4232},{},[4233],{"type":64,"value":4234},"import torch\n",{"type":59,"tag":646,"props":4236,"children":4237},{"class":648,"line":676},[4238],{"type":59,"tag":646,"props":4239,"children":4240},{},[4241],{"type":64,"value":4242},"import torch.nn as nn\n",{"type":59,"tag":646,"props":4244,"children":4245},{"class":648,"line":685},[4246],{"type":59,"tag":646,"props":4247,"children":4248},{"emptyLinePlaceholder":1431},[4249],{"type":64,"value":1434},{"type":59,"tag":646,"props":4251,"children":4252},{"class":648,"line":1400},[4253],{"type":59,"tag":646,"props":4254,"children":4255},{},[4256],{"type":64,"value":4257},"if TYPE_CHECKING:\n",{"type":59,"tag":646,"props":4259,"children":4260},{"class":648,"line":1409},[4261],{"type":59,"tag":646,"props":4262,"children":4263},{},[4264],{"type":64,"value":4265},"    from torch import Tensor\n",{"type":59,"tag":646,"props":4267,"children":4268},{"class":648,"line":1418},[4269],{"type":59,"tag":646,"props":4270,"children":4271},{},[4272],{"type":64,"value":4273},"    from shape_extensions import Elements, Int, IntTuple, IntVar\n",{"type":59,"tag":60,"props":4275,"children":4276},{},[4277,4282],{"type":59,"tag":100,"props":4278,"children":4279},{},[4280],{"type":64,"value":4281},"Runnable (the file is imported\u002Fexecuted):",{"type":64,"value":4283}," a guarded import alone will crash,\nbecause annotations — and PEP 695 type-param bounds — still evaluate at runtime.\nEither:",{"type":59,"tag":108,"props":4285,"children":4286},{},[4287,4343],{"type":59,"tag":112,"props":4288,"children":4289},{},[4290,4292,4298,4300,4305,4307,4312,4314,4319,4320,4325,4327,4333,4335,4341],{"type":64,"value":4291},"add ",{"type":59,"tag":78,"props":4293,"children":4295},{"className":4294},[],[4296],{"type":64,"value":4297},"from __future__ import annotations",{"type":64,"value":4299}," to postpone annotation evaluation,\nand import the symbols that appear in ",{"type":59,"tag":100,"props":4301,"children":4302},{},[4303],{"type":64,"value":4304},"runtime-evaluated",{"type":64,"value":4306}," positions\n(",{"type":59,"tag":78,"props":4308,"children":4310},{"className":4309},[],[4311],{"type":64,"value":334},{"type":64,"value":4313},", plus the bounds ",{"type":59,"tag":78,"props":4315,"children":4317},{"className":4316},[],[4318],{"type":64,"value":320},{"type":64,"value":396},{"type":59,"tag":78,"props":4321,"children":4323},{"className":4322},[],[4324],{"type":64,"value":327},{"type":64,"value":4326}," used in ",{"type":59,"tag":78,"props":4328,"children":4330},{"className":4329},[],[4331],{"type":64,"value":4332},"[Bs: IntTuple]",{"type":64,"value":4334},") at\nmodule top — see ",{"type":59,"tag":78,"props":4336,"children":4338},{"className":4337},[],[4339],{"type":64,"value":4340},"examples\u002Fruntime\u002Fnanogpt_future_annotations_runnable.py",{"type":64,"value":4342},"; or",{"type":59,"tag":112,"props":4344,"children":4345},{},[4346,4348,4354],{"type":64,"value":4347},"import all shape symbols at module top with no guard — see\n",{"type":59,"tag":78,"props":4349,"children":4351},{"className":4350},[],[4352],{"type":64,"value":4353},"examples\u002Fruntime\u002Fgptfast_sym_int_var_runnable.py",{"type":64,"value":810},{"type":59,"tag":60,"props":4356,"children":4357},{},[4358,4363,4365,4370,4372,4378,4380,4385,4387,4392,4393,4398,4400,4405],{"type":59,"tag":78,"props":4359,"children":4361},{"className":4360},[],[4362],{"type":64,"value":312},{"type":64,"value":4364}," binds runtime ints; ",{"type":59,"tag":78,"props":4366,"children":4368},{"className":4367},[],[4369],{"type":64,"value":320},{"type":64,"value":4371}," is the bound for scalar dim params\n(",{"type":59,"tag":78,"props":4373,"children":4375},{"className":4374},[],[4376],{"type":64,"value":4377},"[D: IntVar]",{"type":64,"value":4379},"); ",{"type":59,"tag":78,"props":4381,"children":4383},{"className":4382},[],[4384],{"type":64,"value":327},{"type":64,"value":4386}," is the bound for variadic\u002Fwhole-shape params\n(",{"type":59,"tag":78,"props":4388,"children":4390},{"className":4389},[],[4391],{"type":64,"value":4332},{"type":64,"value":4379},{"type":59,"tag":78,"props":4394,"children":4396},{"className":4395},[],[4397],{"type":64,"value":334},{"type":64,"value":4399}," unpacks a variadic batch\n(",{"type":59,"tag":78,"props":4401,"children":4403},{"className":4402},[],[4404],{"type":64,"value":3088},{"type":64,"value":4406},"). Import only the ones a given file uses.",{"type":59,"tag":60,"props":4408,"children":4409},{},[4410,4415,4417,4422,4424,4430,4432,4438,4440,4446,4448,4454,4456,4461,4463,4468],{"type":59,"tag":70,"props":4411,"children":4412},{},[4413],{"type":64,"value":4414},"Runtime-compatible annotations:",{"type":64,"value":4416}," if you need annotations to evaluate at\nruntime (e.g., for runtime shape validation), import ",{"type":59,"tag":78,"props":4418,"children":4420},{"className":4419},[],[4421],{"type":64,"value":304},{"type":64,"value":4423}," directly\n(not under ",{"type":59,"tag":78,"props":4425,"children":4427},{"className":4426},[],[4428],{"type":64,"value":4429},"TYPE_CHECKING",{"type":64,"value":4431},"). Use old-style ",{"type":59,"tag":78,"props":4433,"children":4435},{"className":4434},[],[4436],{"type":64,"value":4437},"shape_extensions.IntVar",{"type":64,"value":4439}," instead of\nPEP 695 syntax, since ",{"type":59,"tag":78,"props":4441,"children":4443},{"className":4442},[],[4444],{"type":64,"value":4445},"class Foo[T]",{"type":64,"value":4447}," doesn't support arithmetic on ",{"type":59,"tag":78,"props":4449,"children":4451},{"className":4450},[],[4452],{"type":64,"value":4453},"T",{"type":64,"value":4455}," at\nruntime. Alternatively, ",{"type":59,"tag":78,"props":4457,"children":4459},{"className":4458},[],[4460],{"type":64,"value":4297},{"type":64,"value":4462}," defers evaluation\nso annotations never execute, but then ",{"type":59,"tag":78,"props":4464,"children":4466},{"className":4465},[],[4467],{"type":64,"value":91},{"type":64,"value":4469}," becomes a no-op at\nruntime.",{"type":59,"tag":4471,"props":4472,"children":4473},"style",{},[4474],{"type":64,"value":4475},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":4477,"total":4655},[4478,4502,4516,4523,4544,4561,4572,4592,4605,4620,4632,4642],{"slug":4479,"name":4479,"fn":4480,"description":4481,"org":4482,"tags":4483,"stars":4499,"repoUrl":4500,"updatedAt":4501},"relay-best-practices","write idiomatic Relay code","Best practices for writing idiomatic Relay code. ALWAYS use this skill when writing or modifying React components that use Relay for data fetching. Covers fragments, queries, mutations, pagination, and common anti-patterns. Use when you see `useFragment`, `useLazyLoadQuery`, `usePreloadedQuery`, `useMutation`, `usePaginationFragment`, `graphql` template literals, `react-relay` imports, or `__generated__\u002F*.graphql` files. Also use when asked to explain Relay concepts, debug Relay issues, or review Relay code.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4484,4487,4490,4493,4496],{"name":4485,"slug":4486,"type":16},"Engineering","engineering",{"name":4488,"slug":4489,"type":16},"Frontend","frontend",{"name":4491,"slug":4492,"type":16},"GraphQL","graphql",{"name":4494,"slug":4495,"type":16},"React","react",{"name":4497,"slug":4498,"type":16},"Relay","relay",18950,"https:\u002F\u002Fgithub.com\u002Ffacebook\u002Frelay","2026-04-22T04:58:15.370563",{"slug":4503,"name":4503,"fn":4504,"description":4505,"org":4506,"tags":4507,"stars":4499,"repoUrl":4500,"updatedAt":4515},"relay-performance","optimize Relay application performance","Performance best practices for Relay applications. Use when optimizing data fetching, reducing re-renders, configuring caching, or improving time to first meaningful paint. Covers query placement, @defer, pagination, fetch policies, garbage collection, fragment granularity, and server-side filtering. Companion to the relay-best-practices skill which covers correctness and architecture.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4508,4509,4510,4513,4514],{"name":4488,"slug":4489,"type":16},{"name":4491,"slug":4492,"type":16},{"name":4511,"slug":4512,"type":16},"Performance","performance",{"name":4494,"slug":4495,"type":16},{"name":4497,"slug":4498,"type":16},"2026-06-10T07:30:28.726513",{"slug":4,"name":4,"fn":5,"description":6,"org":4517,"tags":4518,"stars":26,"repoUrl":27,"updatedAt":28},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4519,4520,4521,4522],{"name":21,"slug":22,"type":16},{"name":14,"slug":15,"type":16},{"name":24,"slug":25,"type":16},{"name":18,"slug":19,"type":16},{"slug":4524,"name":4524,"fn":4525,"description":4526,"org":4527,"tags":4528,"stars":4541,"repoUrl":4542,"updatedAt":4543},"camera-streaming","configure camera streaming and photo capture","Stream, video frames, photo capture, resolution\u002Fframe rate configuration",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4529,4532,4535,4538],{"name":4530,"slug":4531,"type":16},"Camera","camera",{"name":4533,"slug":4534,"type":16},"Hardware","hardware",{"name":4536,"slug":4537,"type":16},"iOS","ios",{"name":4539,"slug":4540,"type":16},"Video","video",488,"https:\u002F\u002Fgithub.com\u002Ffacebook\u002Fmeta-wearables-dat-ios","2026-05-15T06:14:43.555881",{"slug":4545,"name":4545,"fn":4546,"description":4547,"org":4548,"tags":4549,"stars":4541,"repoUrl":4542,"updatedAt":4560},"dat-conventions","develop iOS applications with DAT SDK","Swift patterns, async\u002Fawait, naming conventions, key types for DAT SDK iOS development",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4550,4551,4554,4557],{"name":4536,"slug":4537,"type":16},{"name":4552,"slug":4553,"type":16},"Mobile","mobile",{"name":4555,"slug":4556,"type":16},"SDK","sdk",{"name":4558,"slug":4559,"type":16},"Swift","swift","2026-05-15T06:14:42.334435",{"slug":4562,"name":4562,"fn":4563,"description":4564,"org":4565,"tags":4566,"stars":4541,"repoUrl":4542,"updatedAt":4571},"debugging","debug wearable device software","Common issues, Developer Mode, version compatibility, state machine diagnosis",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4567,4569,4570],{"name":4568,"slug":4562,"type":16},"Debugging",{"name":4485,"slug":4486,"type":16},{"name":4536,"slug":4537,"type":16},"2026-05-15T06:14:38.626606",{"slug":4573,"name":4573,"fn":4574,"description":4575,"org":4576,"tags":4577,"stars":4541,"repoUrl":4542,"updatedAt":4591},"display-access","manage display capabilities on wearable devices","Display capability setup, display-capable device selection, UI DSL, icons, buttons, images, and video playback",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4578,4581,4584,4587,4590],{"name":4579,"slug":4580,"type":16},"Design","design",{"name":4582,"slug":4583,"type":16},"Images","images",{"name":4585,"slug":4586,"type":16},"Interaction","interaction",{"name":4588,"slug":4589,"type":16},"UI Components","ui-components",{"name":4539,"slug":4540,"type":16},"2026-05-15T06:14:39.844502",{"slug":4593,"name":4593,"fn":4594,"description":4595,"org":4596,"tags":4597,"stars":4541,"repoUrl":4542,"updatedAt":4604},"getting-started","set up Meta wearable SDK integration","SDK setup, Swift Package Manager integration, Info.plist configuration, and first connection to Meta glasses",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4598,4601,4602,4603],{"name":4599,"slug":4600,"type":16},"Configuration","configuration",{"name":4536,"slug":4537,"type":16},{"name":4555,"slug":4556,"type":16},{"name":4558,"slug":4559,"type":16},"2026-05-15T06:14:41.086639",{"slug":4606,"name":4606,"fn":4607,"description":4608,"org":4609,"tags":4610,"stars":4541,"repoUrl":4542,"updatedAt":4619},"mockdevice-testing","test wearable apps with mock devices","MockDeviceKit for testing without physical glasses hardware",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4611,4612,4613,4616],{"name":4536,"slug":4537,"type":16},{"name":4552,"slug":4553,"type":16},{"name":4614,"slug":4615,"type":16},"QA","qa",{"name":4617,"slug":4618,"type":16},"Testing","testing","2026-05-15T06:14:37.406692",{"slug":4621,"name":4621,"fn":4622,"description":4623,"org":4624,"tags":4625,"stars":4541,"repoUrl":4542,"updatedAt":4631},"permissions-registration","register apps with Meta AI","App registration with Meta AI, camera permission flows",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4626,4627,4628],{"name":4530,"slug":4531,"type":16},{"name":4536,"slug":4537,"type":16},{"name":4629,"slug":4630,"type":16},"Permissions","permissions","2026-05-15T06:14:46.030253",{"slug":4633,"name":4633,"fn":4634,"description":4635,"org":4636,"tags":4637,"stars":4541,"repoUrl":4542,"updatedAt":4641},"sample-app-guide","build wearable apps with camera streaming","Building a complete DAT app with camera streaming and photo capture",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4638,4639,4640],{"name":4530,"slug":4531,"type":16},{"name":4536,"slug":4537,"type":16},{"name":4552,"slug":4553,"type":16},"2026-05-15T06:14:36.185947",{"slug":4643,"name":4643,"fn":4644,"description":4645,"org":4646,"tags":4647,"stars":4541,"repoUrl":4542,"updatedAt":4654},"session-lifecycle","monitor device session lifecycle states","Device session states, pause\u002Fresume, availability monitoring",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4648,4649,4650,4653],{"name":4536,"slug":4537,"type":16},{"name":4552,"slug":4553,"type":16},{"name":4651,"slug":4652,"type":16},"Monitoring","monitoring",{"name":4511,"slug":4512,"type":16},"2026-05-15T06:14:44.790925",27,{"items":4657,"total":649},[4658],{"slug":4,"name":4,"fn":5,"description":6,"org":4659,"tags":4660,"stars":26,"repoUrl":27,"updatedAt":28},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4661,4662,4663,4664],{"name":21,"slug":22,"type":16},{"name":14,"slug":15,"type":16},{"name":24,"slug":25,"type":16},{"name":18,"slug":19,"type":16}]