Summary
Follow-up to #2039 / #2046 (single-hop polars). The same marker-before-filter defect exists on the multi-hop paths, on every engine:
- pandas and cuDF:
e_forward({"type": "HAS_CREATOR"}, hops=2, name="type") and the to_fixed_point=True form raise GFQLSchemaError [incompatible-column-type]: column "type" is numeric but filter value is string. The alias marker is written onto the edge frame after hop 1 and hop 2's edge_match then filters the boolean marker.
- polars: serves the same rows; the shadowed column keeps the user values and the marker lands beside it (
<name>_right). That is the pinned polars alias-scoping contract (test_alias_scoping_semantics.py: a shadowed alias reads the user value), not a defect — the two engines differ by design in what the colliding column holds, and agree on rows.
Single-hop steps (hops=1, also multi-step chains where each step is single-hop) are correct on every engine after #2046.
Repro
import pandas as pd, graphistry
from graphistry.compute.ast import n, e_forward
nodes = pd.DataFrame({"key": [1, 2, 3, 4], "id": [10, 20, 30, 40], "type": ["p", "p", "m", "m"]})
edges = pd.DataFrame({"s": [3, 3, 4, 1], "d": [1, 2, 1, 4], "type": ["HAS_CREATOR", "OTHER", "HAS_CREATOR", "OTHER"]})
g = graphistry.nodes(nodes, "key").edges(edges, "s", "d")
g.gfql([n({"id": 30}, name="m"), e_forward({"type": "HAS_CREATOR"}, hops=2, name="type"), n(name="p")]) # raises
g.gfql([n({"id": 30}, name="m"), e_forward({"type": "HAS_CREATOR"}, hops=2, name="e"), n(name="p")]) # control: served
Same with to_fixed_point=True. Found by the alias/column collision probe run for the #2046 review (22 collision shapes × 3 engines × index policy).
Expected
The eager engines serve the multi-hop step like the single-hop one: the step's own edge_match sees the graph's column values on the backward re-execution, and the rows match polars.
Pins
Strict-xfail pins for these shapes live in graphistry/tests/compute/test_chain_alias_column_collision.py (every engine) and flip when this is fixed.
Summary
Follow-up to #2039 / #2046 (single-hop polars). The same marker-before-filter defect exists on the multi-hop paths, on every engine:
e_forward({"type": "HAS_CREATOR"}, hops=2, name="type")and theto_fixed_point=Trueform raiseGFQLSchemaError [incompatible-column-type]: column "type" is numeric but filter value is string. The alias marker is written onto the edge frame after hop 1 and hop 2'sedge_matchthen filters the boolean marker.<name>_right). That is the pinned polars alias-scoping contract (test_alias_scoping_semantics.py: a shadowed alias reads the user value), not a defect — the two engines differ by design in what the colliding column holds, and agree on rows.Single-hop steps (
hops=1, also multi-step chains where each step is single-hop) are correct on every engine after #2046.Repro
Same with
to_fixed_point=True. Found by the alias/column collision probe run for the #2046 review (22 collision shapes × 3 engines × index policy).Expected
The eager engines serve the multi-hop step like the single-hop one: the step's own
edge_matchsees the graph's column values on the backward re-execution, and the rows match polars.Pins
Strict-xfail pins for these shapes live in
graphistry/tests/compute/test_chain_alias_column_collision.py(every engine) and flip when this is fixed.