pgw#993: one flattening rule — carried_by resolves through the same expansion dynamic_shapes mirrors - #516
Merged
Merged
Conversation
… expansion `dynamic_shapes` mirrors
MEASURED (gen-worker 0.93.2, pod `7evvazd2xplzml`, A100-SXM4-80GB, $0.4655):
the z-image AOT mint passed every earlier gate, entered the AOT recipe, and
refused in `trace_graph` — exit=2, `deterministic`, four identical attempts:
entry 'transformer/adapter=true,cfg=true': declared-range gate: declared
dynamic dim names input 'x', which is not a user input of the exported
program (inputs: ['cap_feats_0', 'cap_feats_1', 'lora_a', 'lora_b', 't',
'x_0', 'x_1'])
Two SDK features that each work and could not compose. `Input.repeat`
containers (pgw#853) are FLATTENED by torch.export into one positional user
input per element, suffixed `_0`, `_1`, … for EVERY arity — a one-element
container is `x_0`, never `x` (re-measured here on a real export, both arms).
`Dim.carried_by` names its input by the DECLARED name, and the declared-range
gate resolved that name against the exported program. That makes a `Dim`
carried by a repeated container unsatisfiable BY CONSTRUCTION: naming `x_0`
breaks the `cfg=false` arm, and dropping the dims forfeits `dynamic-collapse`,
which is the reason z-image is 2 entries and not 20.
The fix is the invariant, not the patch. `aot_mint.exported_input_names` is now
the ONE expansion rule: `dynamic_shapes_spec` mirrors the container structure
with it, and `declared_range_gaps` + `lifted_input_gaps` resolve declared names
against exported ones with it — all three from the same per-arm arity map
(`aot_declaration.container_arities`) the example feed was built from, computed
once at the mint call site. A gate that resolves declared names against
exported names must share the name-mangling with the code that produced them;
two independent spellings of one mapping is the defect class, which is why the
lifted-input gate is in this change rather than left for the next rented pod.
Every element is gated, not merely found: a per-element specialization is still
refused, under the element's own name (`x_1[2] exported as the STATIC value
64 …`). Non-container declarations resolve exactly as before (pgw#846).
RED, off-GPU, on the real path (declaration -> export -> gate), reproduced on
BOTH `v0.93.2` and `origin/master` and green here:
N=1 user_inputs=['x_0', 't'] gate(declared names) -> refusal
N=2 user_inputs=['x_0', 'x_1', 't'] gate(declared names) -> refusal
N=1/N=2 with the arity map -> []
tests/test_dim_flattening_pgw993.py drives the pod's program as a double
(user inputs verbatim, refusal string verbatim) and then exports for real on
CPU for both arms of the fork.
PaulFidika
added a commit
that referenced
this pull request
Aug 7, 2026
… expansion `dynamic_shapes` mirrors (#516) MEASURED (gen-worker 0.93.2, pod `7evvazd2xplzml`, A100-SXM4-80GB, $0.4655): the z-image AOT mint passed every earlier gate, entered the AOT recipe, and refused in `trace_graph` — exit=2, `deterministic`, four identical attempts: entry 'transformer/adapter=true,cfg=true': declared-range gate: declared dynamic dim names input 'x', which is not a user input of the exported program (inputs: ['cap_feats_0', 'cap_feats_1', 'lora_a', 'lora_b', 't', 'x_0', 'x_1']) Two SDK features that each work and could not compose. `Input.repeat` containers (pgw#853) are FLATTENED by torch.export into one positional user input per element, suffixed `_0`, `_1`, … for EVERY arity — a one-element container is `x_0`, never `x` (re-measured here on a real export, both arms). `Dim.carried_by` names its input by the DECLARED name, and the declared-range gate resolved that name against the exported program. That makes a `Dim` carried by a repeated container unsatisfiable BY CONSTRUCTION: naming `x_0` breaks the `cfg=false` arm, and dropping the dims forfeits `dynamic-collapse`, which is the reason z-image is 2 entries and not 20. The fix is the invariant, not the patch. `aot_mint.exported_input_names` is now the ONE expansion rule: `dynamic_shapes_spec` mirrors the container structure with it, and `declared_range_gaps` + `lifted_input_gaps` resolve declared names against exported ones with it — all three from the same per-arm arity map (`aot_declaration.container_arities`) the example feed was built from, computed once at the mint call site. A gate that resolves declared names against exported names must share the name-mangling with the code that produced them; two independent spellings of one mapping is the defect class, which is why the lifted-input gate is in this change rather than left for the next rented pod. Every element is gated, not merely found: a per-element specialization is still refused, under the element's own name (`x_1[2] exported as the STATIC value 64 …`). Non-container declarations resolve exactly as before (pgw#846). RED, off-GPU, on the real path (declaration -> export -> gate), reproduced on BOTH `v0.93.2` and `origin/master` and green here: N=1 user_inputs=['x_0', 't'] gate(declared names) -> refusal N=2 user_inputs=['x_0', 'x_1', 't'] gate(declared names) -> refusal N=1/N=2 with the arity map -> [] tests/test_dim_flattening_pgw993.py drives the pod's program as a double (user inputs verbatim, refusal string verbatim) and then exports for real on CPU for both arms of the fork.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
P0. Blocks pgw#868 A2 entirely — z-image is the only family in the fleet using the list-container vocabulary and, before this, it could never mint an AOT cell.
The defect
gen-worker 0.93.2, pod
7evvazd2xplzml(A100-SXM4-80GB), $0.4655: the mint passed every earlier gate, entered the AOT recipe, and refused intrace_graph— exit=2,deterministic, four identical attempts.Two SDK features that each work and could not compose:
Input.repeatcontainers (pgw#853) are flattened bytorch.exportinto one positional user input per element, suffixed_0,_1, … for every arity — a one-element container isx_0, neverx(re-measured here on a real export, both arms of the CFG fork).Dim.carried_bynames its input by the declared name, and the declared-range gate resolved that name against the exported program.So a
Dimcarried by a repeated container was unsatisfiable by construction. No declaration edit fixes it: namingx_0breaks thecfg=falsearm, dropping the dims forfeitsdynamic-collapse— the reason z-image is 2 entries and not 20.The fix — the invariant, not the patch
aot_mint.exported_input_namesis now the ONE expansion rule.dynamic_shapes_specmirrors the container structure with it;declared_range_gapsandlifted_input_gapsresolve declared names against exported ones with it. All three take the same per-arm arity map (aot_declaration.container_arities) the example feed was built from, computed once at the mint call site.A gate that resolves declared names against exported names must share the name-mangling with the code that produced them; two independent spellings of one mapping is the defect class — which is why
lifted_input_gapsis in this change rather than left for the next rented pod (pgw#993 acceptance item 4).Every element is gated, not merely found: a per-element specialization is still refused, under the element's own name. Non-container declarations resolve exactly as before (pgw#846).
RED, off-GPU
tests/test_dim_flattening_pgw993.pydrives the pod's program as a double (user inputs verbatim, refusal string verbatim), then exports for real on CPU for both arms. Reproduced onv0.93.2andorigin/master, green here:11 rows; mypy clean, ruff clean,
lint_http_timeouts/lint_unreached_surface/lint_config_readsgreen; both suites run locally.Also lands on 0.93.3
Per the tracker's release-vehicle rules, this lane cuts no branch and no tag: the mint-speed lane cherry-picks this commit onto
release/0.93.3(based on thev0.93.2tag, pre-wire-v1) alongside pgw#992/pgw#989.Not in scope, filed separately
The serve-side ingress contract has the same shape of gap one gate later:
aot_package.input_contractrecordspositionas the index among exported (flattened) inputs whileaot_serve.bind_call_inputsmatches that position against the caller's pre-flattening args, so a container input binds the whole list to element 0 and shifts every later input. It is unreachable until a container family actually mints — i.e. now. Reported to the tracker rather than folded in here, because it needs its own design (element identity in the contract) and its own RED.