Skip to content

GFQL row pipeline: cuDF host-bridge gap in order_by + test placement debt for compute/gfql/row/ (follow-ups from #1362/#1359) #1373

Description

@lmeyerov

Two related follow-ups surfaced while auditing PR #1362 / #1359 (Comparator + ORDER BY semantics, meta #1353 item #1). Both are non-blocking for #1362 (already merged-ready) but warrant separate work.

1. cuDF host-bridge gap in order_by list-path

While auditing #1362's stringified-list ORDER BY surface for cuDF compatibility, found a latent host-bridge protocol violation at graphistry/compute/gfql/row/pipeline.py:3964.

Setup. parse_stringified_list_series (graphistry/compute/gfql/row/ordering.py:188-219) is intentionally pandas-only — it ast.literal_evals string-encoded lists, which has no cuDF analog. Its docstring documents this and points at the canonical pattern at _gfql_eval_dynamic_list_subscript (pipeline.py:2369-2401).

The gap. The canonical pattern has two halves:

  • Producer (pipeline.py:2394-2401): emits a pd.Series.
  • Consumer (pipeline.py:2424-2437): detects pd.Series and routes around cudf_df.assign(...) via a fresh pd.DataFrame build.

PR #1362's order_by callsite (pipeline.py:3955-3967) implements the producer half but does work_df = work_df.assign(**{sort_col: parsed}) without the consumer-side to_pandas() bridge that select uses at pipeline.py:3651-3658:

if resolve_engine(EngineAbstract.AUTO, table_df) == Engine.CUDF and any(
    isinstance(value, pd.Series) for value in projected.values()
):
    out_table_df = table_df.to_pandas()
    ...

Reachability today. Unreachable in production because the only column dtype that can carry ast.literal_eval-able list strings is pandas string/object, and current upstream gating ensures work_df is already pandas by the time order_by runs. The bug is not a regression in #1362 and not blocking. It is a latent cuDF break that surfaces if either (a) cuDF general object dtype lands or (b) upstream gating regresses.

Coverage gap. Zero _on_cudf tests cover the list / stringified-list / list-comprehension-key ORDER BY surface (52 _on_cudf tests in test_lowering.py, none on this surface). The 8 pin tests at test_lowering.py:7721-7972 are pandas-only by _mk_graph(pd.DataFrame(...)).

Other latent issues found in the same audit (separate, deferrable):

  • ordering.py:306 — only .pivot( call in the whole repo; no established cuDF-safety pattern. Replace with groupby+merge idiom.
  • ordering.py:289 — value_str.where(num_mask, None).astype(\"float64\") is cuDF-fragile (None-fill then float cast).
  • ordering.py:317 — key_frame[col] = key_frame[col].fillna(\"\") is a pure-functional checklist violation per agents/skills/review/SKILL.md.

Proposed work:

  1. Mirror the select consumer-side host-bridge at pipeline.py:3964 (single-line guard).
  2. Add at least one _on_cudf pin test that covers stringified-list ORDER BY on a cuDF input (asserting clean raise OR success, whichever matches expected behavior).
  3. Tighten parse_stringified_list_series docstring to document the caller contract.
  4. (Optional) refactor .pivot( away from build_list_sort_columns:306.
  5. (Optional) where(_, None).astype(\"float64\") cuDF fragility.
  6. (Optional) key_frame[col] = ... mutation fix.

2. Test placement debt: compute/gfql/row/ has no test mirror

PR #1362 added 6 new tests at graphistry/tests/compute/gfql/cypher/test_lowering.py:7781-7972 exercising the cypher → gfql → row-pipeline integration path, but the actual unit-of-change is in graphistry/compute/gfql/row/{ordering,pipeline}.py. These belong in row-pipeline unit tests.

Layout asymmetry

Source Current test home Ideal home
compute/gfql/row/ordering.py tests/compute/gfql/test_row_pipeline_ops.py (2615 LOC, single mega-file) tests/compute/gfql/row/test_ordering.py
compute/gfql/row/pipeline.py same mega-file tests/compute/gfql/row/test_pipeline.py
compute/gfql/row/entity_props.py scattered in same mega-file tests/compute/gfql/row/test_entity_props.py
compute/gfql/row/entity_text.py scattered in same mega-file tests/compute/gfql/row/test_entity_text.py
compute/gfql/row/order_expr.py scattered in same mega-file tests/compute/gfql/row/test_order_expr.py
compute/gfql/row/dispatch.py scattered in same mega-file tests/compute/gfql/row/test_dispatch.py

graphistry/tests/compute/gfql/row/ directory does not exist. Source side has 7 files under row/; test side has zero mirror.

What PR #1362 did

Test Where Should be
test_string_cypher_order_by_python_list_column_uses_list_orderability cypher integration Redundant — duplicates test_row_pipeline_order_by_list_column_matches_opencypher_prefix_tie_break at test_row_pipeline_ops.py:335 (#1360). Drop.
test_string_cypher_order_by_stringified_list_column_uses_list_orderability cypher integration Unit test in test_row_pipeline_ops.py next to :335; keep ONE thin cypher-integration test in test_lowering.py.
test_string_cypher_order_by_partial_stringified_list_raises_mixed_family cypher integration Unit test in test_row_pipeline_ops.py next to peers at :450/:475.
test_string_cypher_order_by_stringified_list_with_nulls_returns_top_k_without_error cypher integration Unit test in test_row_pipeline_ops.py.
test_string_cypher_order_by_malformed_stringified_list_falls_back_to_lex_sort cypher integration Unit test in test_row_pipeline_ops.py.
test_string_cypher_order_by_multi_key_stringified_list_with_scalar cypher integration Unit test in test_row_pipeline_ops.py.

Why this matters

  1. Wrong abstraction layer. Bug class is "row pipeline mishandles stringified lists." Cypher → gfql lowering is unaffected. Testing through cypher adds parse + lower + project noise to every assertion.
  2. Test file bloat. test_lowering.py is 14,732 LOC; test_row_pipeline_ops.py is 2615 LOC. A tests/compute/gfql/row/ subdir splitting per-file would scale better.
  3. Discoverability. A reviewer scanning graphistry/compute/gfql/row/ordering.py for tests has no parallel tests/compute/gfql/row/ to look in.
  4. Coupling to cypher. Row-pipeline tests written through cypher implicitly couple to cypher parser shape; tightening cypher syntax later breaks unrelated row-pipeline pins.

Recommended scope

  • Phase A (small): relocate the 5 useful tests from test_lowering.py:7781-7972 to test_row_pipeline_ops.py (drop the redundant Python-list one); keep one thin cypher-integration smoke test.
  • Phase B (medium): create tests/compute/gfql/row/ subdirectory; split test_row_pipeline_ops.py's 2615 LOC into per-source-file mirrors.
  • Phase C (larger): sweep test_lowering.py for other tests that are really row-pipeline tests and relocate.

Cross-refs

Severity buckets

Status (2026-05-09)

Activity

  1. lmeyerov commented on May 9, 2026

    @lmeyerov
    ContributorAuthor

    Scoped into two concrete follow-up issues for parallel execution:\n\n- #1376 — cuDF host-bridge guard for ORDER BY stringified-list key path\n- #1377 — row test-placement refactor (tests/compute/gfql/row mirror + relocation)\n\nKeeping #1373 as the investigation record; execution should proceed on #1376/#1377.

  2. added 3 commits that reference this issue on May 10, 2026
    e88a002
    cc2aa69
    9eae90a
  3. lmeyerov commented on May 10, 2026

    @lmeyerov
    ContributorAuthor

    Final closure sync after merge of PR #1404:
    #1404

    Validation receipts:

    • PR head after final force-push: 6ea31146ec8fd0d31911b673bb4b59c5133ced47
    • Full GitHub Actions matrix green (including both tck-gfql jobs and docs)
    • DGX GPU validation green on both RAPIDS lanes:
      • RAPIDS_VERSION=25.02 PROFILE=gfql WITH_GPU=1 WITH_IMAGE_BUILD=1 ./docker/test-rapids-official-local.sh -> 343 passed
      • RAPIDS_VERSION=26.02 PROFILE=gfql WITH_GPU=1 WITH_IMAGE_BUILD=1 ./docker/test-rapids-official-local.sh -> 343 passed

    This issue’s host-bridge + row-test-placement follow-through is now landed and validated on CI + DGX.

  4. lmeyerov commented on May 10, 2026

    @lmeyerov
    ContributorAuthor

    Final closure sync after merge of PR #1404: https://github.com/graphistry/pygraphistry/pull/1404\n\nValidation receipts:\n- PR head after final force-push: \n- Full GitHub Actions matrix green (including both jobs and docs)\n- DGX GPU validation green on both RAPIDS lanes:\n - CONFIG
    RAPIDS_VERSION=25.02
    RAPIDS_IMAGE=nvcr.io/nvidia/rapidsai/base:25.02-cuda12.8-py3.12
    PROFILE=gfql
    WITH_GPU=1
    IMAGE_TAG=graphistry/test-rapids-official:25.02-gfql
    PIP_PRE_DEPS=
    PIP_DEPS=-e .[test]
    TEST_FILES=graphistry/tests/compute/gfql/cypher/test_parser.py graphistry/tests/compute/gfql/test_row_pipeline_ops.py graphistry/tests/compute/gfql/cypher/test_lowering.py::test_graph_constructor_cudf_support graphistry/tests/compute/gfql/cypher/test_lowering.py::test_string_cypher_formats_filtered_edge_entity_projection_on_cudf graphistry/tests/compute/gfql/cypher/test_lowering.py::test_string_cypher_executes_real_cugraph_node_row_call_on_cudf -> \n - CONFIG
    RAPIDS_VERSION=26.02
    RAPIDS_IMAGE=nvcr.io/nvidia/rapidsai/base:26.02-cuda12-py3.13
    PROFILE=gfql
    WITH_GPU=1
    IMAGE_TAG=graphistry/test-rapids-official:26.02-gfql
    PIP_PRE_DEPS=
    PIP_DEPS=-e .[test]
    TEST_FILES=graphistry/tests/compute/gfql/cypher/test_parser.py graphistry/tests/compute/gfql/test_row_pipeline_ops.py graphistry/tests/compute/gfql/cypher/test_lowering.py::test_graph_constructor_cudf_support graphistry/tests/compute/gfql/cypher/test_lowering.py::test_string_cypher_formats_filtered_edge_entity_projection_on_cudf graphistry/tests/compute/gfql/cypher/test_lowering.py::test_string_cypher_executes_real_cugraph_node_row_call_on_cudf -> \n\nThis issue’s remaining host-bridge + row-test-placement follow-through is now covered by the merged branch and validated on CI + DGX.

  5. added a commit that references this issue on May 10, 2026
    5c56399
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions