Repository navigation
Honor supplied graph in If path fallback - #9815
Merged
Merged
Conversation
Reuse materializer iterator discovery for the literal-If fallback. Forward the graph under preparation through recursive path inference and cover constrained-graph preparation.
lstein
approved these changes
Oct 11, 2026
lstein
left a comment
Collaborator
There was a problem hiding this comment.
Approving. I ran an adversarial pass on 5186471 and found no blockers. This addresses nits 1 and 2 from my #9786 review.
Verified
- CI is green.
tests/test_graph_execution_state.py+tests/app/services/shared/: 1565 passed, 21 skipped, 2 xfailed. The excludedruntime_import_without_graphtest also passed on my machine.- Ruff check and format check pass.
- Production behavior is unchanged. The only production caller of
prepare()is_prepare_until_node_ready, and it passes_get_source_graph_flat(). That is the graph the fallback used before, and_prepare(base_g)has no callers. - I removed each part of the change one at a time and reran the new test:
| Part of the change removed | New test |
|---|---|
Fallback ignores source_graph |
fails |
prepare() call site drops g |
fails |
_has_admitted_source_mapping call site drops graph |
fails |
Recursive calls stop passing source_graph along (3 separate cases) |
still passes |
Attacks that didn't land
get_node_iteratorsvs the inline scan: they give the same answer. The one difference is theit_graph or ...check, which treats an empty graph as missing. That only matters for an empty iterator graph, which can't happen because the If node comes from the graph it's checked against.- Different object or cache state:
state._materializer()is cached.state._iterator_graphcan route to the For planner's builder, but that runs the sameiterator_graphmethod, and the old code went through the same dispatch.
Non-blocking
- The recursion change is untested. In the test, the inner If has a condition edge, so it returns
[]before it reaches the fallback. Only the top-level If ever usessource_graph, which is why all 3 recursion cases above still pass. A nested literal If that actually reaches the fallback with a constrained graph would cover them. - The test checks a state production can't produce. The constrained graph drops
iteratorand theinner→ifedge, butstate.graphstill has both. The recursion followsstate.graphedges, while the fallback checks the trimmed graph. So the test treats puttingifin the top-level (non-loop) context as correct even though its selected inputinnerruns per loop iteration in the real graph. A "honor the supplied graph" contract only holds together if the edge walk also followsg. No caller needs that today, so you could also trim the test to the plain "use the graph you were given" check. - One spot in
prepare()still ignores the supplied graph. The non-If branch atgraph_materializer.py:1815callsget_node_iterators(next_node_id)withoutg. That fits the If-only scope, but the title suggests more. - My third #9786 nit is still open: iterators on the unselected branch still count as ancestors. That's fine to leave, since it was non-blocking.
Collaborator
Author
|
@lstein Thanks for the review. My plan:
|
Cover recursive source-graph forwarding and preserve short-circuit iterator detection.
Collaborator
|
Re-reviewed 553d204. No blockers, and my approval stands. What changed
Verified
Non-blocking
|
Collaborator
Author
|
@lstein I made the test-only change you requested and updated the PR description. This should be ready to merge. |
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.
Summary
The literal-If path fallback carries the supplied source graph through both If-to-If and non-If recursive paths. A focused regression test places an AddInvocation between nested Ifs and verifies constrained-graph fallback behavior; it fails if the non-If recursive call stops forwarding the supplied graph.
Related Issues / Discussions
Follow-up to #9786 review feedback. Issue #9484 and PR #9789 cover collected Iterate/If deadlock work outside this change.
QA Instructions
PYTHONOPTIMIZE=0 uv run --no-sync pytest -q tests/app/services/shared/test_graph_if_runtime.py tests/test_graph_execution_state.py::test_nested_if_literal_condition_activates_selected_branch -k 'not runtime_import_without_graph'- 13 passed, 1 deselected.free(): invalid pointer; the same failure was reproduced on unchangedmain.git diff --checkpassed.Review
The PR #9786 root-frame fix is already present in
main. The remaining in-scope feedback is addressed, and no material review findings remain.Compatibility / Rollout
Checklist
What's Newcopy (if doing a release after this PR)Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.